文章目录
- Unity UIManager框架学习笔记
- 主要步骤
- 具体实现以及代码
- 1. 制作界面prefab
- 2. 编写json文件存放prefab路径
- 3. 定义一个枚举,包含所有UI界面名字信息
- 4. 定义一个脚本,将json文件反序列化,读取UI界面prefab路径
- 5. 定义BasePanel基类,声明并定义虚函数OnEnter(),OnPause(),OnResume(),OnExit(),若有其他通用功能,添加即可。后面各自UI面板的脚本继承有改动这几个接口时重写即可。
- 6. 定义UIManager脚本,设计为单例模式,方便调用。界面显示和隐藏的思想与栈相似,所以定义一个栈来完成
- 7. 对一个类进行扩展
- 8. 完成各自UI面板脚本的设计,界面动画效果使用DoTween插件
- 9. UIManager启动脚本
Unity UIManager框架学习笔记
主要步骤
- 将所有界面做成prefab并放到resources文件夹下(后面通过resource.load读取)
- 编写一个json文件用于存放prefab的路径
- 定义脚本对json文件进行反序列,读出prefab路径并生成
- 定义一个BasePanel脚本,用于完成所有UI界面的通用功能
- 其他界面的脚本继承BasePanel脚本,完成自己的功能
- 定义一个UIManager单例,用于管理全部UI界面
具体实现以及代码
1. 制作界面prefab
2. 编写json文件存放prefab路径
{
"infoList": [
{
"panelTypeString": "MainMenu",
"path": "UIPanel/MainMenuPanel"
},
{
"panelTypeString": "Task",
"path": "UIPanel/TaskPanel"
}
]
}
3. 定义一个枚举,包含所有UI界面名字信息
public enum UIPanelType
{
MainMenu,
Task,
Knapsack,
Shop,
ItemMessage
}
4. 定义一个脚本,将json文件反序列化,读取UI界面prefab路径
using System;
using UnityEngine;
[Serializable]
public class UIPanelInfo: ISerializationCallbackReceiver//与JsonUtility对应
{
[NonSerialized]
public UIPanelType panelType;
public string panelTypeString;
public string path;
//反序列化,从文本信息到对象
public void OnAfterDeserialize()
{
UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
panelType=type;
}
//序列化
public void OnBeforeSerialize()
{
}
}
5. 定义BasePanel基类,声明并定义虚函数OnEnter(),OnPause(),OnResume(),OnExit(),若有其他通用功能,添加即可。后面各自UI面板的脚本继承有改动这几个接口时重写即可。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BasePanel : MonoBehaviour
{
private CanvasGroup canvasGroup;
public CanvasGroup CanvasGroupValue {
get
{
return canvasGroup;
}
set
{
canvasGroup = value;
}
}
private void Awake()
{
canvasGroup = GetComponent<CanvasGroup>();
}
//UI面板显示时调用
public virtual void OnEnter()
{
canvasGroup.alpha = 1;
canvasGroup.blocksRaycasts = true;
}
//暂停UI面板时调用
public virtual void OnPause()
{
canvasGroup.blocksRaycasts = false;
}
//恢复UI面板交互时调用
public virtual void OnResume()
{
canvasGroup.blocksRaycasts = true;
}
//隐藏UI面板时调用
public virtual void OnExit()
{
canvasGroup.alpha = 0;
canvasGroup.blocksRaycasts = false;
}
public virtual void OnClose()
{
UIManager.Instance.PopPanel();
}
}
6. 定义UIManager脚本,设计为单例模式,方便调用。界面显示和隐藏的思想与栈相似,所以定义一个栈来完成
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UIManager
{
/// <summary>
/// 单例模式
/// </summary>
private static UIManager _instance;
public static UIManager Instance
{
get
{
if(_instance==null)
{
_instance = new UIManager();
}
return _instance;
}
}
private Transform canvasTransform;
private Transform CanvasTransform
{
get
{
if(canvasTransform==null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
private Dictionary<UIPanelType, string> panelPathDict;//所有面板的Prefab的路径
private Dictionary<UIPanelType, BasePanel> panelDict;//保存所有实例化面板身上的base组件
private Stack<BasePanel> panelStack;
private UIManager()
{
ParseUIPanelTypeJson();
}
/// <summary>
/// 把某个页面入栈,即显示界面
/// </summary>
public void PushPanel(UIPanelType panelType)
{
//判断一下栈是否为空
if(panelStack==null)
{
panelStack = new Stack<BasePanel>();
}
//判断一下栈里面是否有页面,有的话将页面暂停
if(panelStack.Count>0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
}
//获得要显示面板的BasePanel
BasePanel panel = GetPanel(panelType);
//调用BasePanel的OnEnter函数
panel.OnEnter();
//显示的面板入栈
panelStack.Push(panel);
}
/// <summary>
/// 把某个页面出栈,即移除
/// </summary>
public void PopPanel()
{
if(panelStack==null)
{
panelStack = new Stack<BasePanel>();
}
if (panelStack.Count <= 0) return;
//关闭栈顶页面显示
BasePanel basePanel = panelStack.Pop();
basePanel.OnExit();
if (panelStack.Count <= 0) return;
BasePanel topPanel = panelStack.Peek();
topPanel.OnResume();
}
/// <summary>
/// 根据面板类型,得到实例化面板
/// </summary>
/// <returns></returns>
private BasePanel GetPanel(UIPanelType panelType)
{
//如果面板对象字典为空,初始化
if(panelDict==null)
{
panelDict = new Dictionary<UIPanelType, BasePanel>();
}
//BasePanel panel;
//panelDict.TryGetValue(panelType, out panel);
//对Direction类进行了扩展,扩展出TryGet方法,简化TryGetValue
BasePanel panel = panelDict.TryGet(panelType);
//如果面板还没实例化出来找不到,那么就找这个面板的路径,然后根据prefab去实例化面板
if (panel==null)
{
//string path;
//panelPathDict.TryGetValue(panelType, out path);
string path = panelPathDict.TryGet(panelType);
GameObject instPanel = GameObject.Instantiate(Resources.Load(path))as GameObject;
instPanel.transform.SetParent(CanvasTransform, false);
panelDict.Add(panelType, instPanel.GetComponent<BasePanel>());
return instPanel.GetComponent<BasePanel>();
}
else
{
return panel;
}
}
[SerializeField]
class UIPanelTypeJson
{
public List<UIPanelInfo> infoList;
}
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<UIPanelType, string>();
//从Rosources中读取json文件
TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
//将json文件反序列
UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);
foreach(UIPanelInfo info in jsonObject.infoList)
{
panelPathDict.Add(info.panelType, info.path);
}
}
}
7. 对一个类进行扩展
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 对Dictory的扩展
/// </summary>
public static class DictionaryExtension
{
/// <summary>
/// 尝试根据key得到value,得到了直接返回value,没有直接返回null
/// </summary>
/// <typeparam name="Tkey"></typeparam>
/// <typeparam name="Tvalue"></typeparam>
/// <param name="dict"></param>
/// <param name=""></param>
public static Tvalue TryGet<Tkey,Tvalue>(this Dictionary<Tkey,Tvalue> dict, Tkey key)
{
Tvalue value;
dict.TryGetValue(key, out value);
return value;
}
}
8. 完成各自UI面板脚本的设计,界面动画效果使用DoTween插件
MainMenuPanel
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MainMenuPanel : BasePanel
{
public void OnPushPanel(string panelTypeString)
{
UIPanelType panelType = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
UIManager.Instance.PushPanel(panelType);
}
}
KnapsackPanel
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class KnapsackPanel : BasePanel
{
public override void OnEnter()
{
CanvasGroupValue.alpha = 0f;
CanvasGroupValue.DOFade(1, 0.5f);
}
public override void OnExit()
{
CanvasGroupValue.DOFade(0, 0.5f);
}
public void OnItemButtonClick()
{
UIManager.Instance.PushPanel(UIPanelType.ItemMessage);
}
}
9. UIManager启动脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameRoot : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
UIManager.Instance.PushPanel(UIPanelType.MainMenu);
}
}