当前位置:   article > 正文

Unity3D基础UI框架,Unity MVVM

unity mvvm

最新:

参考公司lua的mvvm写了一个c#版的,wang-er-s/Framework: a unity mvvm framework, building... (github.com),欢迎提建议

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

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

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

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

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

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

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

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

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

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

  1. using System.Collections;
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.UI;
  6. public class UIManager :MonoBehaviour {
  7. /// <summary>
  8. /// 单例模式:
  9. /// 1.定义一个静态的对象 在外界访问 内部构造
  10. /// 2.构造方法私有化
  11. /// </summary>
  12. #region 单例模式
  13. private static UIManager _instance;
  14. public static UIManager Instance
  15. {
  16. get
  17. {
  18. if (_instance == null)
  19. {
  20. UIManager[] instances = FindObjectsOfType<UIManager>();
  21. if (instances != null)
  22. {
  23. _instance = instances[0];
  24. for (var i = 1; i < instances.Length; i++)
  25. {
  26. Destroy(instances[i].gameObject);
  27. }
  28. }
  29. }
  30. return _instance;
  31. }
  32. }
  33. #endregion
  34. private Transform _canvas;
  35. public Transform Canvas
  36. {
  37. get
  38. {
  39. if (_canvas == null)
  40. _canvas = GameObject.Find("Canvas").transform;
  41. return _canvas;
  42. }
  43. }
  44. //存储所有面板prefab的地址
  45. private Dictionary<UIPanelType, string> _DicPanelPath;
  46. //存储所有实例化的面板身上的BasePanel组件
  47. private Dictionary<UIPanelType, BasePanel> _DicPanel;
  48. //存储所有显示的面板上的BasePanel组件
  49. private Dictionary<UIPanelType, BasePanel> _DicShowPanel;
  50. //表示显示面板的栈
  51. private Stack<BasePanel> _StackPanel;
  52. //全屏显示的节点
  53. private Transform _TraFullScreen = null;
  54. //固定显示的节点
  55. private Transform _TraFixed = null;
  56. //弹出节点
  57. private Transform _TraPopUp = null;
  58. 脚本节点
  59. //private Transform _TraScript = null;
  60. private void Awake()
  61. {
  62. ParseUIPanelPathJson();
  63. _StackPanel = new Stack<BasePanel>();
  64. _DicPanel = new Dictionary<UIPanelType, BasePanel>();
  65. _DicShowPanel = new Dictionary<UIPanelType, BasePanel>();
  66. _TraFullScreen = Canvas.Find("FullScreen");
  67. _TraFixed = Canvas.Find("Fixed");
  68. _TraPopUp = Canvas.Find("PopUp");
  69. DontDestroyOnLoad(Canvas.gameObject);
  70. //_TraScript = Canvas.Find("Script");
  71. }
  72. /// <summary>
  73. /// 把类型为反向切换的窗体入栈
  74. /// </summary>
  75. /// <param name="type"></param>
  76. private void PushPanel(UIPanelType type)
  77. {
  78. BasePanel basePanel = GetPanel(type);
  79. if (_StackPanel.Count >= 1)
  80. {
  81. BasePanel topPanel = _StackPanel.Peek();
  82. topPanel.OnPause();
  83. }
  84. _StackPanel.Push(basePanel);
  85. basePanel.OnEnter();
  86. }
  87. /// <summary>
  88. /// 把类型为反向切换的窗体出栈
  89. /// </summary>
  90. /// <param name="type"></param>
  91. private void PopPanel(UIPanelType type)
  92. {
  93. //如果栈里面为空,则返回
  94. if (_StackPanel.Count <= 0) return;
  95. BasePanel basePanel = GetPanel(type);
  96. BasePanel topPanel = _StackPanel.Peek();
  97. //如果当前要出栈的界面跟栈顶界面相同时 才会出栈
  98. if(basePanel.gameObject == topPanel.gameObject)
  99. {
  100. _StackPanel.Pop();
  101. topPanel.OnExit();
  102. //如果出栈后栈里面还有界面则恢复
  103. if(_StackPanel.Count >= 1)
  104. {
  105. _StackPanel.Peek().OnResume();
  106. }
  107. }
  108. else
  109. {
  110. Debug.LogError("栈顶界面不是此界面,请检查进出栈!!");
  111. }
  112. }
  113. /// <summary>
  114. /// 显示界面
  115. /// </summary>
  116. /// <param name="type"></param>
  117. public void ShowUIForms(UIPanelType type)
  118. {
  119. BasePanel basePanel = GetPanel(type);
  120. switch (basePanel.uiType.uiFormShowMode)
  121. {
  122. case UIFormShowMode.Normal:
  123. EnterUIFormsCache(type);
  124. break;
  125. //如果是反切换类型则入栈
  126. case UIFormShowMode.ReverseChange:
  127. PushPanel(type);
  128. break;
  129. //如果是隐藏其他的类型,清空显示的界面
  130. case UIFormShowMode.HideOther:
  131. HideOtherPanel(type);
  132. break;
  133. }
  134. }
  135. /// <summary>
  136. /// 隐藏界面 如果显示界面字典里面存在此界面
  137. /// </summary>
  138. /// <param name="type"></param>
  139. public void HideUIForms(UIPanelType type)
  140. {
  141. BasePanel basePanel = GetPanel(type);
  142. switch (basePanel.uiType.uiFormShowMode)
  143. {
  144. case UIFormShowMode.Normal:
  145. HideUIFormsCache(type);
  146. break;
  147. //如果是反切换类型则出栈
  148. case UIFormShowMode.ReverseChange:
  149. PopPanel(type);
  150. break;
  151. case UIFormShowMode.HideOther:
  152. HideUIFormsCache(type);
  153. break;
  154. }
  155. }
  156. /// <summary>
  157. /// 隐藏除此之外的Panel,如果不赋值则清空所有
  158. /// </summary>
  159. /// <param name="type"></param>
  160. public void HideOtherPanel(UIPanelType type = UIPanelType.Null)
  161. {
  162. foreach (KeyValuePair<UIPanelType,BasePanel> item in _DicShowPanel)
  163. {
  164. item.Value.OnExit();
  165. }
  166. _DicShowPanel.Clear();
  167. if (type != UIPanelType.Null)
  168. {
  169. BasePanel basePanel = GetPanel(type);
  170. basePanel.OnEnter();
  171. _DicShowPanel.Add(type, GetPanel(type));
  172. }
  173. }
  174. /// <summary>
  175. /// 将UI加入到已显示面板的字典中
  176. /// </summary>
  177. /// <param name="type"></param>
  178. private void EnterUIFormsCache(UIPanelType type)
  179. {
  180. //如果显示面板字典里面有当前面板则返回
  181. if (_DicShowPanel.ContainsKey(type)) return;
  182. BasePanel basePanel = GetPanel(type);
  183. _DicShowPanel.Add(type, basePanel);
  184. basePanel.OnEnter();
  185. }
  186. /// <summary>
  187. /// 将UI隐藏
  188. /// </summary>
  189. /// <param name="type"></param>
  190. private void HideUIFormsCache(UIPanelType type)
  191. {
  192. //如果显示面板字典里面没有当前面板则返回
  193. if (!_DicShowPanel.ContainsKey(type)) return;
  194. BasePanel basePanel = GetPanel(type);
  195. _DicShowPanel.Remove(type);
  196. basePanel.OnExit();
  197. }
  198. /// <summary>
  199. /// 根据面板类型得到实例化的面板
  200. /// </summary>
  201. /// <param name="type"></param>
  202. /// <returns></returns>
  203. private BasePanel GetPanel(UIPanelType type)
  204. {
  205. if (_DicPanel.ContainsKey(type))
  206. {
  207. return _DicPanel[type];
  208. }
  209. else
  210. {
  211. //如果找不到就找这个面板的prefab的路径,然后根据prefab去实例化面板
  212. BasePanel panel;
  213. string panelPath = _DicPanelPath.GetValue(type);
  214. GameObject insGo = GameObject.Instantiate(Resources.Load(panelPath),Canvas) as GameObject;
  215. insGo.name = type.ToString();
  216. panel = insGo.GetComponent<BasePanel>();
  217. switch (panel.uiType.uIFormParentType)
  218. {
  219. case UIFormParentType.FUllScreen:
  220. insGo.transform.SetParent(_TraFullScreen);
  221. break;
  222. case UIFormParentType.Fixed:
  223. insGo.transform.SetParent(_TraFixed);
  224. break;
  225. case UIFormParentType.PopUp:
  226. insGo.transform.SetParent(_TraPopUp);
  227. break;
  228. }
  229. _DicPanel.Add(type, panel);
  230. return panel;
  231. }
  232. }
  233. #region 解析地址json 并存储到字典中
  234. private void ParseUIPanelPathJson()
  235. {
  236. TextAsset text = Resources.Load<TextAsset>("UIPanelType");
  237. JSONObject jSONObject = new JSONObject(text.text);
  238. if (_DicPanelPath == null)
  239. _DicPanelPath = new Dictionary<UIPanelType, string>();
  240. foreach (JSONObject item in jSONObject.list)
  241. {
  242. string panelTypeString = item["panelTypeString"].str;
  243. string path = item["path"].str;
  244. UIPanelType uIPanelType = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
  245. _DicPanelPath.Add(uIPanelType, path);
  246. }
  247. }
  248. #endregion
  249. }
  1. using System.Collections;
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. using UnityEngine.UI;
  6. public class BasePanel : MonoBehaviour {
  7.     protected CanvasGroup cg;
  8.     public UIType uiType;
  9.     private void Awake()
  10.     {
  11.         InitData();
  12.     }
  13.     public virtual void OnCloseBtnClick()
  14.     {
  15.         UIManager.Instance.HideUIForms(uiType.uiPanelType);
  16.     }
  17.     public virtual void InitData()
  18.     {
  19.         if (cg == null)
  20.             cg = this.gameObject.GetAndAddComponent<CanvasGroup>();
  21.         if (uiType == null)
  22.             uiType = new UIType();
  23.     }
  24.     /// <summary>
  25.     /// 界面被显示出来
  26.     /// </summary>
  27.     public virtual void OnEnter()
  28.     {
  29.         cg.alpha = 1;
  30.         cg.blocksRaycasts = true;
  31.         this.gameObject.transform.SetAsLastSibling();
  32.     }
  33.     /// <summary>
  34.     /// 界面暂停 指的是当其他界面在此界面之上,此界面不是主界面的时候,此界面不接受鼠标检测,如果不需要此功能可以适当更改
  35.     /// </summary>
  36.     public virtual void OnPause()
  37.     {
  38.         cg.blocksRaycasts = false;
  39.     }
  40.     /// <summary>
  41.     /// 界面继续
  42.     /// </summary>
  43.     public virtual void OnResume()
  44.     {
  45.         cg.blocksRaycasts = true;
  46.     }
  47.     /// <summary>
  48.     /// 界面不显示,退出这个界面
  49.     /// </summary>
  50.     public virtual void OnExit()
  51.     {
  52.         cg.alpha = 0;
  53.         cg.blocksRaycasts = false;
  54.     }
  55. }

  1. using System.Collections;
  2. using System;
  3. using System.Collections.Generic;
  4. using UnityEngine;
  5. public class UIType {
  6. /// <summary>
  7. /// panel类别
  8. /// </summary>
  9. public UIPanelType uiPanelType;
  10. /// <summary>
  11. /// Panel的显示方式,有正常显示,隐藏其他和反向切换
  12. /// </summary>
  13. public UIFormShowMode uiFormShowMode = UIFormShowMode.Normal;
  14. /// <summary>
  15. /// 这个透明度暂时没用
  16. /// </summary>
  17. public UIFormLucencyType uIFormLucencyType = UIFormLucencyType.Lucency;
  18. /// <summary>
  19. /// Panel的父物体类型
  20. /// </summary>
  21. public UIFormParentType uIFormParentType = UIFormParentType.PopUp;

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

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

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System.Threading.Tasks;
  5. using System;
  6. using UnityEditor;
  7. using System.IO;
  8. using System.Text;
  9. using UnityEngine.UI;
  10. public class UIElement
  11. {
  12. public string Name;
  13. public string Path;
  14. public string ComponentName;
  15. public UIElement(string name,string path,string componentName)
  16. {
  17. Name = name;
  18. Path = path;
  19. ComponentName = componentName;
  20. }
  21. public override string ToString()
  22. {
  23. string str = string.Format("Name={0} || Path={1} || ComponentName={2}", Name, Path, ComponentName);
  24. return str;
  25. }
  26. }
  27. public class UICodeGenerator
  28. {
  29. [MenuItem ( "Assets/CreateCodeDeleteComponent" )]
  30. public static void CreateCodeDeleteComponent ()
  31. {
  32. GetPath ( true );
  33. }
  34. [MenuItem ( "Assets/OnlyCreateCode" )]
  35. public static void OnlyCreateCode ()
  36. {
  37. GetPath ( false );
  38. }
  39. public static void GetPath (bool isDeleteComponent)
  40. {
  41. var objs =
  42. Selection.GetFiltered ( typeof ( GameObject ), SelectionMode.Assets | SelectionMode.TopLevel );
  43. GameObject obj = objs[ 0 ] as GameObject;
  44. elements = new List<UIElement> ();
  45. GetPathAs ( obj.transform, isDeleteComponent );
  46. foreach ( var item in elements )
  47. {
  48. Debug.Log ( item );
  49. }
  50. GeneratePane ( "Assets/" + obj.name + ".cs", obj.name, elements );
  51. GenerateCtrl ( "Assets/" + obj.name + "Ctrl.cs", obj.name, elements );
  52. }
  53. public static List<UIElement> elements;
  54. static void GetPathAs ( Transform transform ,bool isDeleteComponent)
  55. {
  56. foreach ( Transform child in transform )
  57. {
  58. if ( child.gameObject.GetComponent<UIMark> () )
  59. {
  60. elements.Add ( new UIElement ( child.name, GetPath ( child ),
  61. child.gameObject.GetComponent<UIMark> ().ComponentName ) );
  62. if ( isDeleteComponent )
  63. GameObject.DestroyImmediate ( child.gameObject.GetComponent<UIMark> (), true );
  64. }
  65. if ( child.childCount != 0 )
  66. {
  67. GetPathAs ( child, isDeleteComponent );
  68. }
  69. }
  70. }
  71. public static void GeneratePane ( string generateFilePath, string behaviourName, List<UIElement> elements )
  72. {
  73. var sw = new StreamWriter ( generateFilePath, false, Encoding.UTF8 );
  74. var strBuilder = new StringBuilder ();
  75. strBuilder.AppendLine ( "using UnityEngine;" );
  76. strBuilder.AppendLine ( "using UnityEngine.UI;" );
  77. strBuilder.AppendLine ();
  78. strBuilder.AppendFormat ( "public class {0} : BasePanel ", behaviourName );
  79. strBuilder.AppendLine ();
  80. strBuilder.AppendLine ( "{" );
  81. foreach ( var item in elements )
  82. {
  83. strBuilder.AppendLine ( "\tpublic " + item.ComponentName + " " + item.Name + " { get; private set; }" );
  84. }
  85. strBuilder.AppendLine ();
  86. strBuilder.AppendLine ( "\tpublic override void InitData()" );
  87. strBuilder.AppendLine ( "\t{" );
  88. foreach ( var item in elements )
  89. {
  90. strBuilder.AppendFormat ( "\t\t{0} = transform.Find(\"{1}\").GetComponent<{2}>();", item.Name,
  91. item.Path.Replace ( behaviourName + "/", "" ), item.ComponentName );
  92. strBuilder.AppendLine ();
  93. }
  94. strBuilder.AppendLine ();
  95. strBuilder.AppendLine ( "\t\tuiType.uIFormParentType = UIFormParentType.PopUp;" );
  96. strBuilder.AppendLine ( "\t\tuiType.uiFormShowMode = UIFormShowMode.Normal;" );
  97. strBuilder.AppendLine ( "\t\tuiType.uiPanelType = UIPanelType.BoxPanel;" );
  98. strBuilder.AppendLine ( "\t}" );
  99. strBuilder.AppendLine ( "}" );
  100. sw.Write ( strBuilder );
  101. sw.Flush ();
  102. sw.Close ();
  103. AssetDatabase.SaveAssets ();
  104. AssetDatabase.Refresh ();
  105. }
  106. public static void GenerateCtrl ( string generateFilePath, string behaviourName , List<UIElement> elements)
  107. {
  108. var sw = new StreamWriter ( generateFilePath, false, Encoding.UTF8 );
  109. var strBuilder = new StringBuilder ();
  110. List<UIElement> temp = new List<UIElement> ();
  111. foreach ( UIElement element in elements )
  112. {
  113. if(element.ComponentName.Equals("Button"))
  114. temp.Add(element);
  115. }
  116. strBuilder.AppendLine ( "using UnityEngine;" );
  117. strBuilder.AppendLine ( "using UnityEngine.UI;" );
  118. strBuilder.AppendLine ();
  119. strBuilder.AppendFormat ( "public class {0}Ctrl : BaseCtrl ", behaviourName );
  120. strBuilder.AppendLine ( "{" );
  121. strBuilder.AppendLine ();
  122. strBuilder.AppendFormat ( "\tprivate {0} panel;", behaviourName );
  123. strBuilder.AppendLine ();
  124. strBuilder.AppendLine ();
  125. strBuilder.AppendLine ( "\tpublic override void InitPanel()" );
  126. strBuilder.AppendLine ( "\t{" );
  127. strBuilder.AppendFormat ( "\t\tpanel = GetComponent<{0}>();", behaviourName );
  128. strBuilder.AppendLine ();
  129. foreach ( UIElement element in temp )
  130. {
  131. strBuilder.AppendFormat ( "\t\tpanel.{0}.AddListenerGracefully( {1}Click );", element.Name, element.Name );
  132. strBuilder.AppendLine ();
  133. }
  134. strBuilder.AppendLine ( "\t}" );
  135. strBuilder.AppendLine ();
  136. foreach ( UIElement element in temp )
  137. {
  138. strBuilder.AppendFormat ("\tvoid {0}Click()",element.Name);
  139. strBuilder.AppendLine ();
  140. strBuilder.AppendLine ( "\t{" );
  141. strBuilder.AppendLine ();
  142. strBuilder.AppendLine ( "\t}" );
  143. strBuilder.AppendLine ();
  144. }
  145. strBuilder.AppendLine ( "}" );
  146. sw.Write ( strBuilder );
  147. sw.Flush ();
  148. sw.Close ();
  149. AssetDatabase.SaveAssets ();
  150. AssetDatabase.Refresh ();
  151. }
  152. public static string GetPath ( Transform transform )
  153. {
  154. var sb = new System.Text.StringBuilder ();
  155. var t = transform;
  156. while ( true )
  157. {
  158. sb.Insert ( 0, t.name );
  159. t = t.parent;
  160. if ( t )
  161. {
  162. sb.Insert ( 0, "/" );
  163. }
  164. else
  165. {
  166. return sb.ToString ();
  167. }
  168. }
  169. }
  170. }

  1. using UnityEngine.UI;
  2. using UnityEngine;
  3. /// <inheritdoc />
  4. /// <summary>
  5. /// UI的标记
  6. /// </summary>
  7. public class UIMark : MonoBehaviour
  8. {
  9. //public UIMarkType MarkType = UIMarkType.DefaultUnityElement;
  10. public Transform Transform
  11. {
  12. get { return transform; }
  13. }
  14. public string CustomComponentName = "";
  15. public virtual string ComponentName
  16. {
  17. get
  18. {
  19. if ( !string.IsNullOrEmpty ( CustomComponentName ) )
  20. return CustomComponentName;
  21. if (null != GetComponent("SkeletonAnimation"))
  22. return "SkeletonAnimation";
  23. if (null != GetComponent<ScrollRect>())
  24. return "ScrollRect";
  25. if (null != GetComponent<InputField>())
  26. return "InputField";
  27. if (null != GetComponent<Text>())
  28. return "Text";
  29. if (null != GetComponent("TMP.TextMeshProUGUI"))
  30. return "TextMeshProUGUI";
  31. if (null != GetComponent<Button>())
  32. return "Button";
  33. if (null != GetComponent<RawImage>())
  34. return "RawImage";
  35. if (null != GetComponent<Toggle>())
  36. return "Toggle";
  37. if (null != GetComponent<Slider>())
  38. return "Slider";
  39. if (null != GetComponent<Scrollbar>())
  40. return "Scrollbar";
  41. if (null != GetComponent<Image>())
  42. return "Image";
  43. if (null != GetComponent<ToggleGroup>())
  44. return "ToggleGroup";
  45. if (null != GetComponent<Animator>())
  46. return "Animator";
  47. if (null != GetComponent<Canvas>())
  48. return "Canvas";
  49. if (null != GetComponent("Empty4Raycast"))
  50. return "Empty4Raycast";
  51. if (null != GetComponent<RectTransform>())
  52. return "RectTransform";
  53. return "Transform";
  54. }
  55. }
  56. }

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

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/神奇cpp/article/detail/761581
推荐阅读
相关标签
  

闽ICP备14008679号