Unity实现基于UGUI的简易UI框架

匿名 (未验证) 提交于 2019-12-02 22:56:40

Unity实现基于UGUI的简易UI框架

什么是UI框架?

UI框架中的 UIManager 管理场景中所有的面板, 控制面板之间的跳转.

本Demo实现以下功能:

  • 关闭当前页面
  • 显示新的页面
    • 叠加显示
    • 关闭当前页面并显示
    • 关闭所有页面并显示
  • 安卓返回键响应
    • 返回上一个页面
    • 退出程序

设计UI页面

先搭建好所有的UI界面, 并保存为prefab

通过Json和枚举保存所有面板的信息

  • json: json用于描述资料结构,有两种结构存在:

    • 对象 (object):一个对象包含一系列非排序的名称/值对(pair),一个对象以{开始,并以}结束。每个名称/值对之间使用:分区。
    • 数组 (array):一个数组是一个值(value)的集合,一个数组以[开始,并以]结束。数组成员之间使用,分区。数组成员具体的格式如下:
      • 名称/值(pair):名称和值之间使用:隔开,一般的形式是:{name:value}
  • UIPanelType.json: 保存这个工程所有的UI面板类型及其相应的prefab的路径, 此时主要该文件和prefab文件都需要位于Resources文件夹路径下

    { 	"infoList": 		[             {"panelTypeString":"ALERT_PANEL",             "path":"AlertPanel"},              {"panelTypeString":"CONNECT_PANEL",             "path":"ConnectPanel"},              {"panelTypeString":"HOME_PANEL",             "path":"HomePanel"},              {"panelTypeString":"WELCOME_PANEL",             "path":"WelcomePanel"}	 		] } 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

  • UIPanelType.cs: 保存这个工程所有的UI面板类型

    public enum UIPanelType {     ALERT_PANEL,     CONNECT_PANEL,     HOME_PANEL,     WELCOME_PANEL } 
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

开发UIManager解析面板信息Json

  • JsonUtility的使用:
FromJson Create an object from its JSON representation.
FromJsonOverwrite Overwrite data in an object by reading from its JSON representation.
ToJson Generate a JSON representation of the public fields of an object.

注意json中的key值和所对应的unity类中的字段名要保持一致

 [Serializable] public class UIPanelInformation : ISerializationCallbackReceiver {     [NonSerialized]     public UIPanelType panelType;     public string panelTypeString;     public string path;      public void OnAfterDeserialize() {         //反序列化之后, 将一个或多个枚举字符串表示(panelTypeString)转换成等效的枚举对象(UIPanelType)。         UIPanelType type = (UIPanelType)Enum.Parse(typeof(UIPanelType), panelTypeString);         panelType = type;     }     public void OnBeforeSerialize() {         //啥都不用做     } }  [Serializable] public class UIPanelTypeJson { 	//用来储存json对象所对应的类的列表 	public List<UIPanelInformation> infoList; }   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

UIManager.cs中 :

    private void ParseUIPanelTypeJson() {         mPanelPathDictionary = new Dictionary<UIPanelType, string>();         TextAsset textAsset = Resources.Load<TextAsset>("Demo1/UIPanelType");         //将json对象转化为UIPanelTypeJson类         UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(textAsset.text);         foreach (UIPanelInformation info in jsonObject.infoList) {             mPanelPathDictionary.Add(info.panelType, info.path);         }     } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

开发BasePanel面板基类

为什么使用virtual关键字而不是abstract关键字来修饰?

  • 使得子类可以选择是否需要重写方法

控制UI面板Prefab的实例化创建和管理

  • mPanelPathDictionary: 路径字典, 解析保存所有的面板信息(枚举类型和prefab路径)
  • mPanelPool: 实例对象池, 保存所有已实例化的面板
  • mPanelStack: 页面栈, 管理各个页面切换任务

控制面板之间的跳转

主要方法:

  • PushPanel(UIPanelType panelType) : 新增一个页面, 此时当前页面需要被暂停
  • PushPanel(UIPanelType panelType, bool isPopCurrentPanel) : 新增一个页面, 此时当前页面或所有页面需要被关闭
  • BackToLastPanel : 如果mPanelStack.Count为1, 则提示退出程序; 如果不为1, 则弹出当前页面, 并显示此时mPanelStack栈顶页面

其它问题

如何添加新的页面?

  • 制作prefab, 继承BasePanel
  • 重写虚函数
  • 添加枚举类型
  • 添加json信息

如何控制一个面板不可交互 / 忽略点击事件?

  • 了解一下: CanvasGroup 组件, 属性有:

    alpha Set the alpha of the group.设置该组的透明度。
    blocksRaycasts Does this group block raycasting (allow collision).该组是否忽略投射(允许碰撞)。
    ignoreParentGroups Should the group ignore parent groups?是否忽略父物体组?
    interactable Is the group interactable (are the elements beneath the group enabled).是否打开交互(在该组之下启用该元素)。
  • CanvasGroup的典型用途是:

    • 通过在GameObject上添加一个CanvasGroup并控制其Alpha属性来实现整体淡入或淡出。
    • 通过将父物体的CanvasGroup组件中Interactable属性设置为false,从而使子物体一组控件不可交互(“变灰”)。
    • 通过将CanvasGroup组件放置在元素或其父项之一上并将其BlockBlockcast属性设置为false,使一个或多个UI元素不会阻挡鼠标事件(即射线可穿透它)。
  • 参考解决方案:

    1. 组件要求:

    2. 相关代码为:

    [RequireComponent(typeof(CanvasGroup))]  public class BasePanel : MonoBehaviour {     protected CanvasGroup canvasGroup;     protected virtual void Awake() {	         canvasGroup = gameObject.GetComponent<CanvasGroup>();                  //其它代码     }          private void SetPanelInteractable(bool isInteractable) {     	if (isInteractable ^ canvasGroup.interactable) canvasGroup.interactable = isInteractable;     }          //其它代码 }  
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

在游戏运行中如何使得新创建的面板显示在最上面?如何修改UGUI的显示层级?

  • 了解一下: UGUI物体的渲染顺序

    • SetAsFirstSibling:移动到所有兄弟节点的第一个位置(Hierarchy同级最上面,先渲染,显示在最下面
    • SetAsLastSibling:移动到所有兄弟节点的最后一个位置(Hierarchy同级最下面,后渲染,显示在最上面
    • GetSiblingIndex :获得该元素在当前兄弟节点层级的位置
    • SetSiblingIndex :设置该元素在当前兄弟节点层级的位置
  • 参考解决方案:

            gameObject.transform.SetAsLastSibling(); 
    • 1
  • 留意Hierarchy窗口

页面重新出现的时候, AwakeStart函数内的数据刷新不了?

  • 了解一下Unity脚本生命周期:

  • 测试一下, 在Awake, OnEnable, Start, OnDisable, OnEnter, OnExit函数里面加上Debug.Log输出, 结果如图:

AlertPanel.cs的函数调用顺序为:

可见, Awake, Start函数只调用一次, 因此, 每次显示和隐藏页面时的数据操作,可以通过OnEnter, OnExit这两个方法来实现

如果需要切换场景呢?

切换时当前场景内的物体都会被清空, 但我们可以通过DontDestroyOnLoad来保留UIManager单例, 同时将 mPanelPoolmPanelStack清空就好了

    /// <summary>     /// 实例化UIManager     /// </summary>     /// <returns></returns>     private static UIManager GetInstance() {         if (sInstanceUiManager == null) {             var go = new GameObject("UIManager");             sInstanceUiManager = go.AddComponent<UIManager>();             //如果有场景切换             DontDestroyOnLoad(go);         }         return sInstanceUiManager;     }          /// <summary>     /// 切换场景前,调用该方法来清空当前场景的数据     /// </summary>     public void RefreshDataOnSwitchScene() {         mPanelPathDictionary.Clear();         mPanelStack.Clear();     } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

如何切换场景?

        UIManager.Instance.RefreshDataOnSwitchScene();         SceneManager.LoadScene("NewScene"); 
  • 1
  • 2

关于Unity中的序列化

什么是序列化

序列化可以用于跨平台。实际上就是把一段数据翻译成(序列化)比较底层的语言(如汇编、机器语言),而基于这个底层语言再可以翻译(反序列化)成多种上一层的语言。

Unity中的序列化

Unity会自动序列化所有你自己写的脚本组件(Scriptable Object), 重载新的程序集,并且重新创建你的脚本组件。简单的说,序列化后,数据就可以被保存了。Unity序列化过程不走.NET的方法,而是Unity内部的方法。

可序列类型

  • 所有继承自UnityEngine.Object的类,例如 GameObject, Component, MonoBehaviour, Texture2D, AnimationClip.
  • 所有基本数据类型,如 int, string, float, bool等。
  • 一些内置类型,如Vector3、Quaternion,、Matrix4x4、Color、Rect、 LayerMask等。
  • 可序列化类型的数组
  • 可序列化类型的列表
  • 枚举类型
  • 结构类型

Unity可以序列化的有:

  1. 可序列化类型中[公有, 非静态]字段。
  2. [非公有非静态],但是带[SerializeField] 特性的字段。

项目地址

https://github.com/jingangxin36/MyUITools

--------------------- 本文来自 jingangxin36 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/jingangxin666/article/details/80092801?utm_source=co…

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!