一个UI系统-侠岚

在说UI系统的时候,先说一下有点关联的配置管理器,因为有着那么一个配置是ui配置,它记录了ui面板的名称对应的prefab和使用的lua文件,还有一些与其他面板的互斥信息,还有其他情况该不该显示的信息等。

public class GameTableMagr 
    : Singleton<GameTableMagr>
{

    // 加载表格
    public void LoadTable()
    {
        LoadTable("ui", typeof(TableUI));//TableUI
    }
}


在GameTableMagr加载了ui的配置文件后,在GameUIManager单例管理器中去把配置的ui解析为一个一个的UIAsset信息,它保存了配置信息和面板的GameObject和面板的Behaviour等。

public class UIAsset
{
    public TableUI.UI     ui             = null;
    public GameObject     oUIObject    = null;
    public PanelBase    panel         = null;
    public float        timer        = 0;
    public AssetBundle bundle = null;
    public UILuaBehaviour luaBehaviour = null;
}

public class GameUIManager
    : Singleton<GameUIManager>
{

    Dictionary<string, UIAsset>         uiMap         = new Dictionary<string, UIAsset>();
    List<UIAsset>                        uiAllList   = new List<UIAsset>();

    
    public void InitAfterLoadData()
    {
        TableUI table = GameTableMagr.Get().GetTable("ui") as TableUI;
        
        for(int i=0; i<table.uiList.Count; i++)
        {
            if ( i == 1 )
                continue;
            
            UIAsset asset = new UIAsset();
            
            asset.ui = table.uiList[i];
            
            uiMap.Add(asset.ui.name, asset);
            
            uiAllList.Add( asset );
        }

        Resources.UnloadUnusedAssets();
        GC.Collect();
    }
}


UI系统围绕这一个叫做UICmdSystem的单例管理器进行,首先是很多的命令数组,每个命令都是一个字符串,代表的是一个事件。而每一个命令都对应一个UI面板的名称,在所有资源都加载完成和配置加载完成的时候就会初始化命令信息,通过命令的事件为key,对应的面板名字对应的UIAsset为值,放置到一个列表中,多对多的关系。

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

public class UICmd
{
    public string         key = string.Empty;
    public string        values = string.Empty;
}

public class UICmdSystem 
    : Singleton<UICmdSystem>
{
    Hashtable        cmdList = null;
    Queue<UICmd>    cmdQueue = null;
    
    string []    regCmd =
    {
        "update_gold",
    };
    
    string[,]    regUI =
    {
        {"update_gold",                 "Main"},
    };
    
    public void Initial()
    {
        cmdList = new Hashtable();
        cmdQueue= new Queue<UICmd>();
        
        for(int i=0; i<regCmd.Length; i++)
            RegCmd(regCmd[i]);
    }
    
    public void InitAfterLoadData()
    {
        for(int i=0; i<regUI.GetLength(0); i++)
            RegUICmd(regUI[i,0], regUI[i,1]);
    }
    
    void RegCmd(string key)
    {
        if(cmdList.ContainsKey(key))
            return;
        cmdList.Add(key, new List<UIAsset>());
    }
    
    void RegUICmd(string key, string panel)
    {
        if(cmdList.ContainsKey(key) == false)
        {
            Debug.LogError("[UICmdSystem] UICmd:" + key + ",not register!" );
            return;
        }

        UIAsset asset = GameUIManager.Get().GetUIAsset(panel);
        if(asset == null)
        {
            Debug.LogError("[UICmdSystem] UICmd:" + key + ",Panel:" + panel + ",not ui" );
            return;
        }
        
        List<UIAsset> list = cmdList[key] as List<UIAsset>;
        if(list.Contains(asset))
        {
            Debug.LogError("[UICmdSystem] UICmd:" + key + ",Panel:" + panel + ",has register" );
            return;
        }
        
        list.Add(asset);
    }
    
    public void AddCommand(UICmd cmd)
    {
        if(cmd == null)
            return;
        if(cmdList.ContainsKey(cmd.key) == false)
            return;
        cmdQueue.Enqueue(cmd);
    }
    
    public void Tick()//Tick方法会在Main里面的Update方法调用
    {        
        while(cmdQueue.Count != 0)
        {
            UICmd cmd = cmdQueue.Dequeue();
            //Debug.LogError(cmd.key + " | " + cmd.values);
            if(cmd == null)
                continue;
            
            List<UIAsset> uiAsset = cmdList[cmd.key] as List<UIAsset>;

            for(int i=0; i<uiAsset.Count; i++)
            {
                UIAsset asset = uiAsset[i];
                if(asset == null)
                    continue;
                if ((asset.panel == null && asset.luaBehaviour == null) || asset.oUIObject == null)
                    continue;
                if (asset.luaBehaviour != null) {
                    asset.luaBehaviour.HandleCommand(cmd);
                }
                if (asset.panel != null) {
                    asset.panel.HandleCommand(cmd);
                }
            }
        }
        cmdQueue.Clear();
    }
    
    public bool HaveCommand(UICmd cmd)
    {
        if(cmd == null)
            return false;
        if(cmdList.ContainsKey(cmd.key) == false)
            return false;
        
        UICmd[] cmds = cmdQueue.ToArray();
        for(int i = 0; i < cmds.Length; i ++)
        {
            if(cmd.key == cmds[i].key)
                return true;
        }
        return false;
    }
}


看上面的UICmdSystem就知道了,它当前已经知道哪些命令归哪些UI去处理了,当我们需要通知一个事件的时候,通过单例的UICmdSystem的AddCommand方法添加到列表里面,在Update里面就会取出来,找到命令key对应的UIAsset,再在里面找到脚本(UI面板),调用其的HandleCommand方法处理事件,并将UICmd传递进去,通过UICmd.values区分命令处理。

public override void ValueChange(UICmd cmd)//HandleCommand方法调用了ValueChange虚方法,用来给具体的Panel重写的
{
    if (!m_isInit)
        initUI();
    if (cmd.key.Equals("loginselect_ver"))
    {
        if (cmd.values.Equals("loadLocVer"))
        {
            curVersion.gameObject.SetActive(true);
            curVersion.text = CorResMgr.Get().locVer;
        }
        else if (cmd.values.Equals("update"))
        {
            curProgTxt.gameObject.SetActive(true);
            curProgTxt.text = CorResMgr.Get().infoTxt;
            progBar.gameObject.SetActive(true);
            progBar.value = 0.0f;
            
            updateProgCheck = StartCoroutine(updateProg());
        }
    }
}

首页 我的博客
粤ICP备17103704号