Unity-简单的UI框架

这套UI框架是基于Unity目前主流的UGUI的,虽说目前Unity官方正在开发新的UIToolkit,但是目前还是预览版。这个框架我在多个项目中使用了,内容比较简单、实用,在此记录一下,方便以后使用。

一、首先这个框架是细分到一个个UI窗口上的,所以第一个类是WindowBase

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class WindowBase : MonoBehaviour
{
    //皮肤路径
    public string skinPath;
    //皮肤
    public GameObject skin;
    //层级
    public UIManager.Layer layer = UIManager.Layer.Panel;
    //初始化
    public void Init(){
        //皮肤
        GameObject skinPrefab = Resources.Load<GameObject>(skinPath);
        skin = (GameObject)Instantiate(skinPrefab);
    }
    //关闭
    public void Close(){
        string name = this.GetType().ToString();
        UIManager.Close(name);
    }

    //初始化时
    public virtual void OnInit(){
    }
    //显示时
    public virtual void OnShow(params object[] para){
    }
    //关闭时
    public virtual void OnClose(){
    }
}

二、第二个类是UIManager

using System.Collections.Generic;
using UnityEngine;

//UIManager不用继承于Monobehaviour,里面都是静态方法
public class UIManager
{
    //Layer对应不同的层级
    public enum Layer{
        Panel,
        Tip,//一般用作弹框
    }
    //层级列表
    private static Dictionary<Layer, Transform> layers = new Dictionary<Layer, Transform>();
    //面板列表
    public static Dictionary<string, WindowBase> panels = new Dictionary<string, WindowBase>();
    //结构
    public static Transform canvas;
    //初始化
    public static void Init(){
        canvas = GameObject.Find("Canvas").transform;
        Transform panel = canvas.Find("Panel");
        Transform tip = canvas.Find("Tip");
        layers.Add(Layer.Panel, panel);
        layers.Add(Layer.Tip, tip);
    }

    //打开面板
    public static void Open<T>(params object[] para) where T:WindowBase{
        //已经打开
        string name = typeof(T).ToString();
        if (panels.ContainsKey(name)){
            return;
        }
        //组件
        WindowBase panel = canvas.gameObject.AddComponent<T>();
        panel.OnInit();
        panel.Init();
        //父容器
        Transform layer = layers[panel.layer];
        panel.skin.transform.SetParent(layer, false);
        //列表
        panels.Add(name, panel);
        //OnShow
        panel.OnShow(para);
    }

    //关闭面板
    public static void Close(string name){
        WindowBase panel = panels[name];
        //没有打开
        if (panel == null){
            return;
        }
        //OnClose
        panel.OnClose();
        //列表
        panels.Remove(name);
        //销毁
        GameObject.Destroy(panel.skin);
        Component.Destroy(panel);
    }

    //关闭所有 
    //在跳转场景时候删除了所有ui所以要closeall,为了防止再次进入该场景时候字典中重复添加。但是如果用的是dontdestroyonload就不需要了
    public static void CloseAll()
    {
        foreach(var i in panels)
        {
            WindowBase panel = i.Value;
            //没有打开
            if (panel == null){
                return;
            }
            panel.OnClose();
            //销毁
            GameObject.Destroy(panel.skin);
            Component.Destroy(panel);
        }
        panels.Clear();
        layers.Clear();
    }
}

三、完成上面两个类,我的框架的主体基本就有了,为了对框架有一个初始化,我们还需要写一个程序入口类,并且在该类中对UIManager初始化。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//APP入口
public class MainEntry : MonoBehaviour
{
    void Start()
    {
        UIManager.Init();
        UIManager.Open<MainWindow>();
    }

    private void OnDestroy() {
        UIManager.CloseAll();
    }

}

四、接下来我们完成一个主UI的实现。

第一步是在Inspector窗口中添加我们的canvas,然后再创建两个子物体分别命名为Plane和Tip用来对应我们在UIManager中定义的两种层级,同时把自动生成的EventSystem也放在Canvas底下。效果如图所示。

然后再来制作我们的第一个UI界面——MainUI,这个界面很简单,只有几个按钮,如图所示,值得注意的是要把这个界面的根节点设置为跟随父级大小。最后我们把这个UI制作成预制体,放在我们的Resources文件夹中,方便我们使用代码加载。

然后就是写我们的UI逻辑代码了。我是在OnInit方法中设置预制体的路径和层级,在OnShow方法中对UI逻辑初始化。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

//主面板
public class MainWindow : WindowBase
{
    private Button InfoButton;
    private Button CreateButton;
    private Button ExitButton;

    public override void OnInit()
    {
        base.OnInit();
        skinPath = "UIPrefab/MainPanel";
        layer = UIManager.Layer.Panel;
    }

    public override void OnShow(params object[] para)
    {
        base.OnShow(para);
        InfoButton = skin.transform.Find("Upper/InfoButton").GetComponent<Button>();
        CreateButton = skin.transform.Find("Upper/CreateButton").GetComponent<Button>();
        ExitButton = skin.transform.Find("Upper/ExitButton").GetComponent<Button>();

        InfoButton.onClick.AddListener(InfoButtonClick);
        CreateButton.onClick.AddListener(CreateButtonClick);
        ExitButton.onClick.AddListener(ExitButtonClick);
    }

    public override void OnClose()
    {
        base.OnClose();
    }

    private void InfoButtonClick()
    {
        UIManager.Open<CreatePanel>();
    }

    private void CreateButtonClick()
    {
        UIManager.Open<WithItemPanel>();
    }

    private void ExitButtonClick()
    {
        string tip = "是否关闭?";
        Action callback = new Action(CloseAppCallback);
        UIManager.Open<PopupPanel>(tip,callback);
    }

    private void CloseAppCallback()
    {
        print("当前程序正在退出!");
        Application.Quit();
    }
}

我在MainEntry中已经把打开这个窗口的代码已经写上了。

UIManager.Open<MainWindow>();

这个时候我们运行程序就回打开我们的MainUI了。

框架到此就结束了,目前来说这些功能已经能够满足我们做一些中小型项目的需求了,并且使用起来也很方便。我也不想把它扩展的很庞大复杂。

这里是源码:下载地址

 

点赞

发表回复

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像