Unity UIManager框架学习笔记

Unity UIManager框架学习笔记

在这里插入图片描述

主要步骤

  1. 将所有界面做成prefab并放到resources文件夹下(后面通过resource.load读取)
  2. 编写一个json文件用于存放prefab的路径
  3. 定义脚本对json文件进行反序列,读出prefab路径并生成
  4. 定义一个BasePanel脚本,用于完成所有UI界面的通用功能
  5. 其他界面的脚本继承BasePanel脚本,完成自己的功能
  6. 定义一个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);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值