PoorMonk

UIFramwork(Unity3D)

目标:UIFramewrok教程学习笔记

知识点:

1 图片导入后要把Texture Type修改为Sprite(2D and UI)。

2 画布的Canvas Scaler(Script)组件中的UI Scale Mode属性改为Scale With Screen Size,Match属性改为1,对应Height,这样画布就能自适应屏幕大小。

序列化 : 目的是以某种存储形式使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。简单来说就是将对象保存到文件中(比如Unity中的场景文件和预制体默认就是以二进制文件保存在工程目录)

Unity序列化

  • SerializeField:表示变量可被序列化。与private、protected结合使用可以达到让脚本的变量在检视面板里可视化编辑,同时保持它的私有性的目的。
  • HideInInspector:将原本显示在检视面板上的序列化值隐藏起来。
  • NonSerialized:将一个公有变量不序列化并且不现实在检视面板中。
  • Serializable:用在类的前面,表示该类可被序列化。

举例:

public class Test :Monobehavior
{
    public int  a;                               //序列化,显示
    private int b;                               //不序列化,不显示
    [SerializeField ] int c;                     //序列化,显示
    [HideInInspector] public int d;              //序列化,不显示
    [NonSerialized ] public int e;               //不序列化,不显示
    public Test2 test2;                          //序列化,显示(可序列化的部分)
}

[Serializable ]
public class Test2
{
     public int aa;
     private int bb;
}

将此脚本挂在预制体下,用Sublime打开预制体可看到:

a:0
c:0
d:0
test2:
	aa:0

注意:并非所有的公有变量都可以被序列化。其中const,static变量无法序列化。链表和字典在内存中的存储不连续,也无法序列化。

从文件中导入JSon对象:

using UnityEngine;

[System.Serializable]
public class PlayerInfo
{
    public string name;
    public int lives;
    public float health;

    public static PlayerInfo CreateFromJSON(string jsonString)
    {
        return JsonUtility.FromJson<PlayerInfo>(jsonString);
    }

    // Given JSON input:
    // {"name":"Dr Charles","lives":3,"health":0.8}
    // this example will return a PlayerInfo object with
    // name == "Dr Charles", lives == 3, and health == 0.8f.
}

创建的对象必须是可序列化的,每个字段对应一个Key值(名字要一样)。由于不能直接识别Enum类型,所以先用string类型替代,在反序列化(从文本里读取到对象)之后再转换,比如:

[Serializable]
public class UIPanelInfo : ISerializationCallbackReceiver {

    [NonSerialized] public UIPanelType panelType;  //Enum类型不序列化
    public string panelTypeString;
    public string path;

    //反序列化 从文本信息到对象
    public void OnAfterDeserialize()   //实现接口函数
    {
        UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
        panelType = type;
    }

    public void OnBeforeSerialize()
    {
        throw new NotImplementedException();
    }
}

扩展Dictionary类,能直接获取每个键对应的值,不用先定义再以参数的形式获取

public static class DictionaryExtension {

	public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue = default(TValue))
    {
        return dict.ContainsKey(key) ? dict[key] : defaultValue;
    }
}

UIFramewrok

1 为所有页面Panel创建一个基类BasePanel,抽象四个虚函数(显示,暂停,恢复,关闭)用来操作界面

public class BasePanel : MonoBehaviour {

    public virtual void OnEnter() {}
    
    public virtual void OnPause() {}
   
    public virtual void OnResume() {}

    public virtual void OnExit() {}
}

2 为每一个页面添加一个对应的枚举类型

public enum UIPanelType {
    ItemMessage,
    Knapsack,
    MainMenu,
    Shop,
    Skill,
    System,
    Task
}

3 在JSon文件中保存每个页面的类型信息以及预制体路径

{
  "panelInfoList": [
    {
      "panelTypeString": "ItemMessage",
      "path": "UIPanel/ItemMessagePanel"
    },
    {
      "panelTypeString": "Knapsack",
      "path": "UIPanel/KnapsackPanel"
    },
    {
      "panelTypeString": "MainMenu",
      "path": "UIPanel/MainMenuPanel"
    },
    {
      "panelTypeString": "Shop",
      "path": "UIPanel/ShopPanel"
    },
    {
      "panelTypeString": "Skill",
      "path": "UIPanel/SkillPanel"
    },
    {
      "panelTypeString": "Task",
      "path": "UIPanel/TaskPanel"
    },
    {
      "panelTypeString": "System",
      "path": "UIPanel/SystemPanel"
    }
  ]
}

4 用单例模式创建一个管理类UIManager来管理所有界面

public class UIManager  {
    private Dictionary<UIPanelType, string> panelPathDict; //存储所有面板Prefab的路径
    private Dictionary<UIPanelType, BasePanel> panelDict;  //存储所有实例化的Panel的BasePanel组件
    private Stack<BasePanel> panelStack; //存储所有的Panel来控制界面状态
    private static UIManager _instance;
    private Transform canvasTransform;
    public Transform CanvasTransform
    {
        get
        {
            if (canvasTransform == null)
            {
                canvasTransform = GameObject.Find("Canvas").transform;
            }
            return canvasTransform;
        }
    }

    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
    }  

    private UIManager()
    {
        ParsePanleTypeJson();
    }

    public void PushPanel(UIPanelType panelType)  // 显示界面接口
    {
        if (null == panelStack)
        {
            panelStack = new Stack<BasePanel>();
        }

        if (0 < panelStack.Count)
        {
            BasePanel topPanel = panelStack.Peek();
            topPanel.OnPause();
        }

        BasePanel panel = GetPanel(panelType);
        panel.OnEnter();
        panelStack.Push(panel);
    }

    public void PopPanel(UIPanelType panelType) // 关闭界面接口
    {
        if (null == panelStack)
            return;

        if (panelStack.Count < 0)
            return;
        BasePanel topPanel = panelStack.Pop();
        topPanel.OnExit();

        if (panelStack.Count < 0)
            return;
        topPanel = panelStack.Peek();
        topPanel.OnResume();  // 恢复上个界面的状态
    }

    [Serializable]
    public class PanelTypeJsonList
    {
        public List<UIPanelInfo> panelInfoList;
    }

	// 读取JSon文件中所有界面的路径
    private void ParsePanleTypeJson() 
    {
        panelPathDict = new Dictionary<UIPanelType, string>();
        TextAsset ta = Resources.Load<TextAsset>("UIPanelType");
        PanelTypeJsonList panelList = JsonUtility.FromJson<PanelTypeJsonList>(ta.text);
        foreach (UIPanelInfo info in panelList.panelInfoList)
        {	           
            panelPathDict.Add(info.panelType, info.path);
        }
    }

    private BasePanel GetPanel(UIPanelType panelType)
    {       
        if (panelDict == null)
        {
            panelDict = new Dictionary<UIPanelType, BasePanel>();
        }

        BasePanel panel = panelDict.TryGet(panelType);
        if (null == panel)
        {
            string path = panelPathDict.TryGet(panelType);          
            GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;
            instPanel.transform.SetParent(CanvasTransform, false);
            panel = instPanel.GetComponent<BasePanel>();
            panelDict.Add(panelType, panel);
        }

        return panel;
    }
}

完整项目源码地址:https://github.com/PoorMonk/UIFramework

posted on 2018-06-19 10:21  PoorMonk  阅读(58)  评论(0)    收藏  举报

导航