Unity3D基础UI框架,Unity MVVM

最新:

参考公司lua的mvvm写了一个c#版的,https://github.com/so-sos-so/SoF,欢迎提建议

后续会新开一篇文章补充开发思路

------------------------------弃用---------------------------------

之前学了刘国柱老师的UI框架加上我自己的理解做了一个UI框架正好可以使用

这里附上刘国柱老师的博客 http://www.cnblogs.com/LiuGuozhu/ 受益颇深

Unity3D基础UI框架,Unity MVVM_第1张图片

Unity3D基础UI框架,Unity MVVM_第2张图片

基本UI框架的类图就是这样了

大体是根据MVC加上我的魔改而成的框架,至少我自己暂时觉得还是思路挺清晰的

Panel的切换是使用的Canvas Group的更改透明度,在加上使用

此方法来更改显示顺序和显隐的

其中的界面反向切换是使用的栈后入先出的特性

反向切换是指一个窗口弹出小窗口后,父窗口的Raycast需要取消,下面贴上核心代码

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

public class UIManager :MonoBehaviour {

    /// 
    /// 单例模式:
    /// 1.定义一个静态的对象 在外界访问 内部构造
    /// 2.构造方法私有化
    /// 
    #region 单例模式

    private static UIManager _instance;

    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                UIManager[] instances = FindObjectsOfType();
                if (instances != null)
                {
                    _instance = instances[0];
                    for (var i = 1; i < instances.Length; i++)
                    {
                        Destroy(instances[i].gameObject);
                    }
                }
            }
            return _instance;
        }
    }

    #endregion


    private Transform _canvas;
    public Transform Canvas
    {
        get
        {
            if (_canvas == null)
                _canvas = GameObject.Find("Canvas").transform;
            return _canvas;
        }
    }
    //存储所有面板prefab的地址
    private Dictionary _DicPanelPath;
    //存储所有实例化的面板身上的BasePanel组件
    private Dictionary _DicPanel;
    //存储所有显示的面板上的BasePanel组件
    private Dictionary _DicShowPanel;
    //表示显示面板的栈
    private Stack _StackPanel;
    //全屏显示的节点
    private Transform _TraFullScreen = null;
    //固定显示的节点
    private Transform _TraFixed = null;
    //弹出节点
    private Transform _TraPopUp = null;
    脚本节点
    //private Transform _TraScript = null;


    private void Awake()
    {
        ParseUIPanelPathJson();
        _StackPanel = new Stack();
        _DicPanel = new Dictionary();
        _DicShowPanel = new Dictionary();
        _TraFullScreen = Canvas.Find("FullScreen");
        _TraFixed = Canvas.Find("Fixed");
        _TraPopUp = Canvas.Find("PopUp");
        DontDestroyOnLoad(Canvas.gameObject);
        //_TraScript = Canvas.Find("Script");
    }



    /// 
    /// 把类型为反向切换的窗体入栈
    /// 
    /// 
    private void PushPanel(UIPanelType type)
    {
        BasePanel basePanel = GetPanel(type);
        if (_StackPanel.Count >= 1)
        {
            BasePanel topPanel = _StackPanel.Peek();
            topPanel.OnPause();
        }
        _StackPanel.Push(basePanel);
        basePanel.OnEnter();
    }

    /// 
    /// 把类型为反向切换的窗体出栈
    /// 
    /// 
    private void PopPanel(UIPanelType type)
    {
        //如果栈里面为空,则返回
        if (_StackPanel.Count <= 0) return;
        BasePanel basePanel = GetPanel(type);
        BasePanel topPanel = _StackPanel.Peek();
        //如果当前要出栈的界面跟栈顶界面相同时 才会出栈
        if(basePanel.gameObject == topPanel.gameObject)
        {
            _StackPanel.Pop();
            topPanel.OnExit();
            //如果出栈后栈里面还有界面则恢复
            if(_StackPanel.Count >= 1)
            {
                _StackPanel.Peek().OnResume();
            }
        }
        else
        {
            Debug.LogError("栈顶界面不是此界面,请检查进出栈!!");
        }
        
    }

    /// 
    /// 显示界面
    /// 
    /// 
    public void ShowUIForms(UIPanelType type)
    {
        BasePanel basePanel = GetPanel(type);
        switch (basePanel.uiType.uiFormShowMode)
        {
            case UIFormShowMode.Normal:
                EnterUIFormsCache(type);
                break;
            //如果是反切换类型则入栈
            case UIFormShowMode.ReverseChange:
                PushPanel(type);
                break;
            //如果是隐藏其他的类型,清空显示的界面
            case UIFormShowMode.HideOther:
                HideOtherPanel(type);
                break;
        }
    }

    /// 
    /// 隐藏界面 如果显示界面字典里面存在此界面
    /// 
    /// 
    public void HideUIForms(UIPanelType type)
    {
        BasePanel basePanel = GetPanel(type);

        switch (basePanel.uiType.uiFormShowMode)
        {
            case UIFormShowMode.Normal:
                HideUIFormsCache(type);
                break;
            //如果是反切换类型则出栈
            case UIFormShowMode.ReverseChange:
                PopPanel(type);
                break;
            case UIFormShowMode.HideOther:
                HideUIFormsCache(type);
                break;
        }
    }

    /// 
    /// 隐藏除此之外的Panel,如果不赋值则清空所有
    /// 
    /// 
    public void HideOtherPanel(UIPanelType type = UIPanelType.Null)
    {
        foreach (KeyValuePair item in _DicShowPanel)
        {
            item.Value.OnExit();
        }
        _DicShowPanel.Clear();
        if (type != UIPanelType.Null)
        {
            BasePanel basePanel = GetPanel(type);
            basePanel.OnEnter();
            _DicShowPanel.Add(type, GetPanel(type));
        }
            
    }

    /// 
    /// 将UI加入到已显示面板的字典中
    /// 
    /// 
    private void EnterUIFormsCache(UIPanelType type)
    {
        //如果显示面板字典里面有当前面板则返回
        if (_DicShowPanel.ContainsKey(type)) return;
        BasePanel basePanel = GetPanel(type);
        _DicShowPanel.Add(type, basePanel);
        basePanel.OnEnter();
    }

    /// 
    /// 将UI隐藏
    /// 
    /// 
    private void HideUIFormsCache(UIPanelType type)
    {
        //如果显示面板字典里面没有当前面板则返回
        if (!_DicShowPanel.ContainsKey(type)) return;
        BasePanel basePanel = GetPanel(type);
        _DicShowPanel.Remove(type);
        basePanel.OnExit();
    }

    /// 
    /// 根据面板类型得到实例化的面板
    /// 
    /// 
    /// 
    private BasePanel GetPanel(UIPanelType type)
    {
        if (_DicPanel.ContainsKey(type))
        {
            return _DicPanel[type];
        }
        else
        {
            //如果找不到就找这个面板的prefab的路径,然后根据prefab去实例化面板
            BasePanel panel;
            string panelPath = _DicPanelPath.GetValue(type);
            GameObject insGo = GameObject.Instantiate(Resources.Load(panelPath),Canvas) as GameObject;
            insGo.name = type.ToString();
            panel = insGo.GetComponent();
            switch (panel.uiType.uIFormParentType)
            {
                case UIFormParentType.FUllScreen:
                    insGo.transform.SetParent(_TraFullScreen);
                    break;
                case UIFormParentType.Fixed:
                    insGo.transform.SetParent(_TraFixed);
                    break;
                case UIFormParentType.PopUp:
                    insGo.transform.SetParent(_TraPopUp);
                    break;
            }
            _DicPanel.Add(type, panel);
            return panel;
        }
    }

    #region 解析地址json 并存储到字典中
    
    private void ParseUIPanelPathJson()
    {
        TextAsset text = Resources.Load("UIPanelType");
        JSONObject jSONObject = new JSONObject(text.text);
        if (_DicPanelPath == null)
            _DicPanelPath = new Dictionary();
        foreach (JSONObject item in jSONObject.list)
        {
            string panelTypeString = item["panelTypeString"].str;
            string path = item["path"].str;
            UIPanelType uIPanelType = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
            _DicPanelPath.Add(uIPanelType, path);
        }
    }

    #endregion

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


public class BasePanel : MonoBehaviour {


    protected CanvasGroup cg;
    public UIType uiType;


    private void Awake()
    {
        InitData();
    }


    public virtual void OnCloseBtnClick()
    {
        UIManager.Instance.HideUIForms(uiType.uiPanelType);
    }


    public virtual void InitData()
    {
        if (cg == null)
            cg = this.gameObject.GetAndAddComponent();
        if (uiType == null)
            uiType = new UIType();
    }




    /// 
    /// 界面被显示出来
    /// 
    public virtual void OnEnter()
    {
        cg.alpha = 1;
        cg.blocksRaycasts = true;
        this.gameObject.transform.SetAsLastSibling();
    }


    /// 
    /// 界面暂停 指的是当其他界面在此界面之上,此界面不是主界面的时候,此界面不接受鼠标检测,如果不需要此功能可以适当更改
    /// 
    public virtual void OnPause()
    {
        cg.blocksRaycasts = false;
    }


    /// 
    /// 界面继续
    /// 
    public virtual void OnResume()
    {
        cg.blocksRaycasts = true;
    }


    /// 
    /// 界面不显示,退出这个界面
    /// 
    public virtual void OnExit()
    {
        cg.alpha = 0;
        cg.blocksRaycasts = false;
    }
	
}

 

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

public class UIType  {

    /// 
    /// panel类别
    /// 
    public UIPanelType uiPanelType;
    /// 
    /// Panel的显示方式,有正常显示,隐藏其他和反向切换
    /// 
    public UIFormShowMode uiFormShowMode = UIFormShowMode.Normal;
    /// 
    /// 这个透明度暂时没用
    /// 
    public UIFormLucencyType uIFormLucencyType = UIFormLucencyType.Lucency;
    /// 
    /// Panel的父物体类型
    /// 
    public UIFormParentType uIFormParentType = UIFormParentType.PopUp;

 

代码比较多,不过都有贴心的注释

 

-------------------------------加了一个代码自动生成的工具-----------------------------------

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;
using System;
using UnityEditor;
using System.IO;
using System.Text;
using UnityEngine.UI;

public class UIElement
{
    public string Name;
    public string Path;
    public string ComponentName;
    public UIElement(string name,string path,string componentName)
    {
        Name = name;
        Path = path;
        ComponentName = componentName;
    }

    public override string ToString()
    {
        string str = string.Format("Name={0} || Path={1} || ComponentName={2}", Name, Path, ComponentName);
        return str;
    }
}

public class UICodeGenerator
{
    [MenuItem ( "Assets/CreateCodeDeleteComponent" )]
    public static void CreateCodeDeleteComponent ()
    {
        GetPath ( true );
    }
    
    [MenuItem ( "Assets/OnlyCreateCode" )]
    public static void OnlyCreateCode ()
    {
        GetPath ( false );
    }
    
    public static void GetPath (bool isDeleteComponent)
    {
        var objs =
            Selection.GetFiltered ( typeof ( GameObject ), SelectionMode.Assets | SelectionMode.TopLevel );
        GameObject obj = objs[ 0 ] as GameObject;
        elements = new List ();
        GetPathAs ( obj.transform, isDeleteComponent );

        foreach ( var item in elements )
        {
            Debug.Log ( item );
        }

        GeneratePane ( "Assets/" + obj.name + ".cs", obj.name, elements );
        GenerateCtrl ( "Assets/" + obj.name + "Ctrl.cs", obj.name, elements );

    }

    public static List elements;

    static void GetPathAs ( Transform transform ,bool isDeleteComponent)
    {
        foreach ( Transform child in transform )
        {
            if ( child.gameObject.GetComponent () )
            {
                elements.Add ( new UIElement ( child.name, GetPath ( child ),
                                               child.gameObject.GetComponent ().ComponentName ) );
                if ( isDeleteComponent )
                    GameObject.DestroyImmediate ( child.gameObject.GetComponent (), true );
            }

            if ( child.childCount != 0 )
            {
                GetPathAs ( child, isDeleteComponent );
            }
        }
    }


    public static void GeneratePane ( string generateFilePath, string behaviourName, List elements )
    {
        var sw         = new StreamWriter ( generateFilePath, false, Encoding.UTF8 );
        var strBuilder = new StringBuilder ();

        strBuilder.AppendLine ( "using UnityEngine;" );
        strBuilder.AppendLine ( "using UnityEngine.UI;" );
        strBuilder.AppendLine ();
        strBuilder.AppendFormat ( "public class {0} : BasePanel ", behaviourName );
        strBuilder.AppendLine ();
        strBuilder.AppendLine ( "{" );
        foreach ( var item in elements )
        {
            strBuilder.AppendLine ( "\tpublic " + item.ComponentName + " " + item.Name + " { get; private set; }" );
        }

        strBuilder.AppendLine ();
        strBuilder.AppendLine ( "\tpublic override void InitData()" );
        strBuilder.AppendLine ( "\t{" );
        foreach ( var item in elements )
        {
            strBuilder.AppendFormat ( "\t\t{0} = transform.Find(\"{1}\").GetComponent<{2}>();", item.Name,
                                      item.Path.Replace ( behaviourName + "/", "" ), item.ComponentName );
            strBuilder.AppendLine ();
        }

        strBuilder.AppendLine ();
        strBuilder.AppendLine ( "\t\tuiType.uIFormParentType = UIFormParentType.PopUp;" );
        strBuilder.AppendLine ( "\t\tuiType.uiFormShowMode = UIFormShowMode.Normal;" );
        strBuilder.AppendLine ( "\t\tuiType.uiPanelType = UIPanelType.BoxPanel;" );
        strBuilder.AppendLine ( "\t}" );
        strBuilder.AppendLine ( "}" );
        sw.Write ( strBuilder );
        sw.Flush ();
        sw.Close ();

        AssetDatabase.SaveAssets ();
        AssetDatabase.Refresh ();
    }

    public static void GenerateCtrl ( string generateFilePath, string behaviourName , List elements)
    {
        var sw         = new StreamWriter ( generateFilePath, false, Encoding.UTF8 );
        var strBuilder = new StringBuilder ();

        List temp = new List ();
        
        foreach ( UIElement element in elements )
        {
            if(element.ComponentName.Equals("Button"))
                temp.Add(element);
        }
        
        strBuilder.AppendLine ( "using UnityEngine;" );
        strBuilder.AppendLine ( "using UnityEngine.UI;" );
        strBuilder.AppendLine ();
        strBuilder.AppendFormat ( "public class {0}Ctrl : BaseCtrl ", behaviourName );
        strBuilder.AppendLine ( "{" );
        strBuilder.AppendLine ();
        strBuilder.AppendFormat ( "\tprivate {0} panel;", behaviourName );
        strBuilder.AppendLine ();
        strBuilder.AppendLine ();
        strBuilder.AppendLine ( "\tpublic override void InitPanel()" );
        strBuilder.AppendLine ( "\t{" );
        strBuilder.AppendFormat ( "\t\tpanel = GetComponent<{0}>();", behaviourName );
        strBuilder.AppendLine ();
        foreach ( UIElement element in temp )
        {
            strBuilder.AppendFormat ( "\t\tpanel.{0}.AddListenerGracefully( {1}Click );", element.Name, element.Name );
            strBuilder.AppendLine ();
        }
        strBuilder.AppendLine ( "\t}" );
        strBuilder.AppendLine ();
        foreach ( UIElement element in temp )
        {
            strBuilder.AppendFormat ("\tvoid {0}Click()",element.Name);
            strBuilder.AppendLine ();
            strBuilder.AppendLine ( "\t{" );
            strBuilder.AppendLine ();
            strBuilder.AppendLine ( "\t}" );
            strBuilder.AppendLine ();
        }

        strBuilder.AppendLine ( "}" );
        sw.Write ( strBuilder );
        sw.Flush ();
        sw.Close ();

        AssetDatabase.SaveAssets ();
        AssetDatabase.Refresh ();
    }

    public static string GetPath ( Transform transform )
    {
        var sb = new System.Text.StringBuilder ();
        var t  = transform;
        while ( true )
        {
            sb.Insert ( 0, t.name );
            t = t.parent;
            if ( t )
            {
                sb.Insert ( 0, "/" );
            }
            else
            {
                return sb.ToString ();
            }
        }
    }
}

 

 

using UnityEngine.UI;
using UnityEngine;

/// 
/// 
/// UI的标记
/// 
public class UIMark : MonoBehaviour
{
    //public UIMarkType MarkType = UIMarkType.DefaultUnityElement;

    public Transform Transform
    {
        get { return transform; }
    }

    public string CustomComponentName = "";
    
    public virtual string ComponentName
    {
        get
        {
            if ( !string.IsNullOrEmpty ( CustomComponentName ) )
                return CustomComponentName;
            if (null != GetComponent("SkeletonAnimation"))
                return "SkeletonAnimation";
            if (null != GetComponent())
                return "ScrollRect";
            if (null != GetComponent())
                return "InputField";
            if (null != GetComponent())
                return "Text";
            if (null != GetComponent("TMP.TextMeshProUGUI"))
                return "TextMeshProUGUI";
            if (null != GetComponent

使用方法,把需要使用的组件加上UIMark标记,拖成预设体,右键点击自动生成代码,就会自动生成视图和控制层

-------------------------------弃用-------------------------------------

思想可以借鉴,但是使用起来不是很方便

最新版框架借鉴QFramework,喜欢的可以去看看

你可能感兴趣的:(Unity3D)