UI管理模块——UI基类

帮助面板通过代码快速找到各类子控件

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. /// <summary>
  7. /// 面板基类
  8. /// 找到所有自己面板下的控件对象
  9. /// 他应该提供显示或隐藏的行为
  10. /// </summary>
  11. public class BasePanel : MonoBehaviour
  12. {
  13. // 通过里氏转换原则, 来存储所有的控件
  14. private Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();
  15. void Awake()
  16. {
  17. FindChildrenControl<Button>();
  18. FindChildrenControl<Image>();
  19. FindChildrenControl<Text>();
  20. FindChildrenControl<Toggle>();
  21. FindChildrenControl<Slider>();
  22. FindChildrenControl<ScrollRect>();
  23. }
  24. /// <summary>
  25. /// 显示自己
  26. /// </summary>
  27. public virtual void ShowMe(){}
  28. /// <summary>
  29. /// 隐藏自己
  30. /// </summary>
  31. public virtual void HideMe(){}
  32. /// <summary>
  33. /// 找到子对象的对应控件
  34. /// </summary>
  35. /// <typeparam name="T"></typeparam>
  36. private void FindChildrenControl<T>() where T : UIBehaviour
  37. {
  38. T[] controls = this.GetComponentsInChildren<T>();
  39. string objName;
  40. for (int i = 0; i < controls.Length; i++)
  41. {
  42. objName = controls[i].gameObject.name;
  43. if (controlDic.ContainsKey(objName))
  44. {
  45. controlDic[objName].Add(controls[i]);
  46. }
  47. else
  48. {
  49. controlDic.Add(objName, new List<UIBehaviour>() { controls[i] });
  50. }
  51. }
  52. }
  53. /// <summary>
  54. /// 得到对应名字的脚本
  55. /// </summary>
  56. /// <typeparam name="T"></typeparam>
  57. /// <param name="controlName"></param>
  58. /// <returns></returns>
  59. protected T GetControl<T>(string controlName) where T : UIBehaviour
  60. {
  61. if (controlDic.ContainsKey(controlName))
  62. {
  63. for (int i = 0; i < controlDic[controlName].Count; ++i)
  64. {
  65. if (controlDic[controlName][i] is T)
  66. {
  67. return controlDic[controlName][i] as T;
  68. }
  69. }
  70. }
  71. return null;
  72. }
  73. }

UI管理模块——UI管理器

管理所有显示的面板,提供给其他游戏系统接口,用来显示面板和隐藏面板

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. /// <summary>
  6. /// UI层级枚举
  7. /// </summary>
  8. public enum E_UI_Layer
  9. {
  10. Bot,
  11. Mid,
  12. Top,
  13. System
  14. }
  15. public class UIManager : BaseManager<UIManager>
  16. {
  17. public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();
  18. //private Transform canvas;
  19. // 为UI分层
  20. private Transform bot; // 底层
  21. private Transform mid; // 中层
  22. private Transform top; // 顶层
  23. private Transform system; // 系统层
  24. // 记录UI的Canvas父对象 方便以后外部可能会使用他
  25. public RectTransform canvas;
  26. public UIManager()
  27. {
  28. // 创建Canvas, 让其过场景不移除
  29. GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");
  30. canvas = obj.transform as RectTransform;
  31. GameObject.DontDestroyOnLoad(obj);
  32. // 找到各层
  33. bot = canvas.Find("Bot");
  34. mid = canvas.Find("Mid");
  35. top = canvas.Find("Top");
  36. system = canvas.Find("System");
  37. // 创建EventSystem
  38. obj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");
  39. GameObject.DontDestroyOnLoad(obj);
  40. }
  41. /// <summary>
  42. /// 显示面板
  43. /// </summary>
  44. /// <typeparam name="T">面板脚本类型</typeparam>
  45. /// <param name="panelName">面板名</param>
  46. /// <param name="layer">显示在哪一层</param>
  47. /// <param name="callBack">当面板预设体创建成功后, 想要做的事</param>
  48. public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T : BasePanel
  49. {
  50. // 面板已经存在
  51. if (panelDic.ContainsKey(panelName))
  52. {
  53. panelDic[panelName].ShowMe();
  54. if (callBack != null)
  55. {
  56. callBack(panelDic[panelName] as T);
  57. }
  58. //// 避免面板重复加载, 如果存在该面板则直接显示, 调用回调函数后, 直接Return, 不再处理后面的异步加载
  59. return;
  60. }
  61. // 异步加载面板
  62. ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>
  63. {
  64. // 把他作为Canvas的子对象, 并且要设置他的相对位置
  65. // 找到父对象 , 显示在哪一层
  66. Transform father = bot;
  67. switch (layer)
  68. {
  69. case E_UI_Layer.Mid:
  70. father = mid;
  71. break;
  72. case E_UI_Layer.Top:
  73. father = top;
  74. break;
  75. case E_UI_Layer.System:
  76. father = system;
  77. break;
  78. }
  79. // 设置父对象, 相对位置和大小
  80. obj.transform.SetParent(father,false);
  81. obj.transform.localPosition = Vector3.zero;
  82. obj.transform.localScale = Vector3.one;
  83. (obj.transform as RectTransform).offsetMax = Vector2.zero;
  84. (obj.transform as RectTransform).offsetMin = Vector2.zero;
  85. // 得到预设体上的的面板脚本
  86. T panel = obj.GetComponent<T>();
  87. // 处理面板创建完成后的逻辑 (因为是异步加载面板, 要做延时处理, 只有当面板真正加载完时, 才会做外面想要做的事情.)
  88. if (callBack != null)
  89. {
  90. callBack(panel);
  91. }
  92. panelDic[panelName].ShowMe();
  93. // 把面板存起来
  94. panelDic.Add(panelName, panel);
  95. });
  96. }
  97. /// <summary>
  98. /// 隐藏面板
  99. /// </summary>
  100. /// <param name="panelName">面板名</param>
  101. public void HidePanel(string panelName)
  102. {
  103. if (panelDic.ContainsKey(panelName))
  104. {
  105. panelDic[panelName].HideMe();
  106. GameObject.Destroy(panelDic[panelName].gameObject);
  107. panelDic.Remove(panelName);
  108. }
  109. }
  110. /// <summary>
  111. /// 得到某一个已经显示的面板
  112. /// </summary>
  113. /// <param name="panelName">面板名</param>
  114. public T GetPanel<T>(string panelName)where T:BasePanel
  115. {
  116. if(panelDic.ContainsKey(panelName))
  117. {
  118. return panelDic[panelName] as T;
  119. }
  120. return null;
  121. }
  122. }

使用

image.png

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class UITest : MonoBehaviour
  5. {
  6. void Start()
  7. {
  8. UIManager.GetInstance().ShowPanel<LoginPanel>("LoginPanel", E_UI_Layer.Bot, showPanelOver);
  9. }
  10. private void showPanelOver(LoginPanel panel)
  11. {
  12. panel.IninInfo();
  13. Invoke("DelayHide", 1);
  14. }
  15. private void DelayHide()
  16. {
  17. UIManager.GetInstance().HidePanel("LoginPanel");
  18. }
  19. }

UI管理模块——优化面板基类事件监听

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. /// <summary>
  7. /// 面板基类
  8. /// 帮助我门通过代码快速的找到所有的子控件
  9. /// 方便我们在子类中处理逻辑
  10. /// 节约找控件的工作量
  11. /// </summary>
  12. public class BasePanel : MonoBehaviour
  13. {
  14. //通过里式转换原则 来存储所有的控件
  15. private Dictionary<string, List<UIBehaviour>> controlDic = new Dictionary<string, List<UIBehaviour>>();
  16. // Use this for initialization
  17. protected virtual void Awake () {
  18. FindChildrenControl<Button>();
  19. FindChildrenControl<Image>();
  20. FindChildrenControl<Text>();
  21. FindChildrenControl<Toggle>();
  22. FindChildrenControl<Slider>();
  23. FindChildrenControl<ScrollRect>();
  24. FindChildrenControl<InputField>();
  25. }
  26. /// <summary>
  27. /// 显示自己
  28. /// </summary>
  29. public virtual void ShowMe()
  30. {
  31. }
  32. /// <summary>
  33. /// 隐藏自己
  34. /// </summary>
  35. public virtual void HideMe()
  36. {
  37. }
  38. protected virtual void OnClick(string btnName)
  39. {
  40. }
  41. protected virtual void OnValueChanged(string toggleName, bool value)
  42. {
  43. }
  44. /// <summary>
  45. /// 得到对应名字的对应控件脚本
  46. /// </summary>
  47. /// <typeparam name="T"></typeparam>
  48. /// <param name="controlName"></param>
  49. /// <returns></returns>
  50. protected T GetControl<T>(string controlName) where T : UIBehaviour
  51. {
  52. if(controlDic.ContainsKey(controlName))
  53. {
  54. for( int i = 0; i <controlDic[controlName].Count; ++i )
  55. {
  56. if (controlDic[controlName][i] is T)
  57. return controlDic[controlName][i] as T;
  58. }
  59. }
  60. return null;
  61. }
  62. /// <summary>
  63. /// 找到子对象的对应控件
  64. /// </summary>
  65. /// <typeparam name="T"></typeparam>
  66. private void FindChildrenControl<T>() where T:UIBehaviour
  67. {
  68. T[] controls = this.GetComponentsInChildren<T>();
  69. for (int i = 0; i < controls.Length; ++i)
  70. {
  71. string objName = controls[i].gameObject.name;
  72. if (controlDic.ContainsKey(objName))
  73. controlDic[objName].Add(controls[i]);
  74. else
  75. controlDic.Add(objName, new List<UIBehaviour>() { controls[i] });
  76. //如果是按钮控件
  77. if(controls[i] is Button)
  78. {
  79. (controls[i] as Button).onClick.AddListener(()=>
  80. {
  81. OnClick(objName);
  82. });
  83. }
  84. //如果是单选框或者多选框
  85. else if(controls[i] is Toggle)
  86. {
  87. (controls[i] as Toggle).onValueChanged.AddListener((value) =>
  88. {
  89. OnValueChanged(objName, value);
  90. });
  91. }
  92. }
  93. }
  94. }
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. /// <summary>
  6. /// UI层级
  7. /// </summary>
  8. public enum E_UI_Layer
  9. {
  10. Bot,
  11. Mid,
  12. Top,
  13. System,
  14. }
  15. /// <summary>
  16. /// UI管理器
  17. /// 1.管理所有显示的面板
  18. /// 2.提供给外部 显示和隐藏等等接口
  19. /// </summary>
  20. public class UIManager : BaseManager<UIManager>
  21. {
  22. public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();
  23. private Transform bot;
  24. private Transform mid;
  25. private Transform top;
  26. private Transform system;
  27. //记录我们UI的Canvas父对象 方便以后外部可能会使用它
  28. public RectTransform canvas;
  29. public UIManager()
  30. {
  31. //创建Canvas 让其过场景的时候 不被移除
  32. GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");
  33. canvas = obj.transform as RectTransform;
  34. GameObject.DontDestroyOnLoad(obj);
  35. //找到各层
  36. bot = canvas.Find("Bot");
  37. mid = canvas.Find("Mid");
  38. top = canvas.Find("Top");
  39. system = canvas.Find("System");
  40. //创建EventSystem 让其过场景的时候 不被移除
  41. obj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");
  42. GameObject.DontDestroyOnLoad(obj);
  43. }
  44. /// <summary>
  45. /// 通过层级枚举 得到对应层级的父对象
  46. /// </summary>
  47. /// <param name="layer"></param>
  48. /// <returns></returns>
  49. public Transform GetLayerFather(E_UI_Layer layer)
  50. {
  51. switch(layer)
  52. {
  53. case E_UI_Layer.Bot:
  54. return this.bot;
  55. case E_UI_Layer.Mid:
  56. return this.mid;
  57. case E_UI_Layer.Top:
  58. return this.top;
  59. case E_UI_Layer.System:
  60. return this.system;
  61. }
  62. return null;
  63. }
  64. /// <summary>
  65. /// 显示面板
  66. /// </summary>
  67. /// <typeparam name="T">面板脚本类型</typeparam>
  68. /// <param name="panelName">面板名</param>
  69. /// <param name="layer">显示在哪一层</param>
  70. /// <param name="callBack">当面板预设体创建成功后 你想做的事</param>
  71. public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T:BasePanel
  72. {
  73. if (panelDic.ContainsKey(panelName))
  74. {
  75. panelDic[panelName].ShowMe();
  76. // 处理面板创建完成后的逻辑
  77. if (callBack != null)
  78. callBack(panelDic[panelName] as T);
  79. //避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后 直接return 不再处理后面的异步加载逻辑
  80. return;
  81. }
  82. ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>
  83. {
  84. //把他作为 Canvas的子对象
  85. //并且 要设置它的相对位置
  86. //找到父对象 你到底显示在哪一层
  87. Transform father = bot;
  88. switch(layer)
  89. {
  90. case E_UI_Layer.Mid:
  91. father = mid;
  92. break;
  93. case E_UI_Layer.Top:
  94. father = top;
  95. break;
  96. case E_UI_Layer.System:
  97. father = system;
  98. break;
  99. }
  100. //设置父对象 设置相对位置和大小
  101. obj.transform.SetParent(father);
  102. obj.transform.localPosition = Vector3.zero;
  103. obj.transform.localScale = Vector3.one;
  104. (obj.transform as RectTransform).offsetMax = Vector2.zero;
  105. (obj.transform as RectTransform).offsetMin = Vector2.zero;
  106. //得到预设体身上的面板脚本
  107. T panel = obj.GetComponent<T>();
  108. // 处理面板创建完成后的逻辑
  109. if (callBack != null)
  110. callBack(panel);
  111. panel.ShowMe();
  112. //把面板存起来
  113. panelDic.Add(panelName, panel);
  114. });
  115. }
  116. /// <summary>
  117. /// 隐藏面板
  118. /// </summary>
  119. /// <param name="panelName"></param>
  120. public void HidePanel(string panelName)
  121. {
  122. if(panelDic.ContainsKey(panelName))
  123. {
  124. panelDic[panelName].HideMe();
  125. GameObject.Destroy(panelDic[panelName].gameObject);
  126. panelDic.Remove(panelName);
  127. }
  128. }
  129. /// <summary>
  130. /// 得到某一个已经显示的面板 方便外部使用
  131. /// </summary>
  132. public T GetPanel<T>(string name) where T:BasePanel
  133. {
  134. if (panelDic.ContainsKey(name))
  135. return panelDic[name] as T;
  136. return null;
  137. }
  138. }
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using UnityEngine.UI;
  6. public class LoginPanel : BasePanel {
  7. //public Button btnStart;
  8. //public Button btnQuit;
  9. protected override void Awake()
  10. {
  11. //一定不能少 因为需要执行父类的awake来初始化一些信息 比如找控件 加事件监听
  12. base.Awake();
  13. //在下面处理自己的一些初始化逻辑
  14. }
  15. // Use this for initialization
  16. void Start () {
  17. //GetControl<Button>("btnStart").onClick.AddListener(ClickStart);
  18. //GetControl<Button>("btnQuit").onClick.AddListener(ClickQuit);
  19. UIManager.AddCustomEventListener(GetControl<Button>("btnStart"), EventTriggerType.PointerEnter, (data)=>{
  20. Debug.Log("进入");
  21. });
  22. UIManager.AddCustomEventListener(GetControl<Button>("btnStart"), EventTriggerType.PointerExit, (data) => {
  23. Debug.Log("离开");
  24. });
  25. }
  26. private void Drag(BaseEventData data)
  27. {
  28. }
  29. private void PointerDown(BaseEventData data)
  30. {
  31. }
  32. // Update is called once per frame
  33. void Update () {
  34. }
  35. public override void ShowMe()
  36. {
  37. base.ShowMe();
  38. //显示面板时 想要执行的逻辑 这个函数 在UI管理器中 会自动帮我们调用
  39. //只要重写了它 就会执行里面的逻辑
  40. }
  41. protected override void OnClick(string btnName)
  42. {
  43. switch(btnName)
  44. {
  45. case "btnStart":
  46. Debug.Log("btnStart被点击");
  47. break;
  48. case "btnQuit":
  49. Debug.Log("btnQuit被点击");
  50. break;
  51. }
  52. }
  53. protected override void OnValueChanged(string toggleName, bool value)
  54. {
  55. //在这来根据名字判断 到底是那一个单选框或者多选框状态变化了 当前状态就是传入的value
  56. }
  57. public void InitInfo()
  58. {
  59. Debug.Log("初始化数据");
  60. }
  61. //点击开始按钮的处理
  62. public void ClickStart()
  63. {
  64. }
  65. //点击开始按钮的处理
  66. public void ClickQuit()
  67. {
  68. Debug.Log("S");
  69. }
  70. }

UI管理模块——自定义事件监听

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. using UnityEngine.EventSystems;
  6. /// <summary>
  7. /// UI层级
  8. /// </summary>
  9. public enum E_UI_Layer
  10. {
  11. Bot,
  12. Mid,
  13. Top,
  14. System,
  15. }
  16. /// <summary>
  17. /// UI管理器
  18. /// 1.管理所有显示的面板
  19. /// 2.提供给外部 显示和隐藏等等接口
  20. /// </summary>
  21. public class UIManager : BaseManager<UIManager>
  22. {
  23. public Dictionary<string, BasePanel> panelDic = new Dictionary<string, BasePanel>();
  24. private Transform bot;
  25. private Transform mid;
  26. private Transform top;
  27. private Transform system;
  28. //记录我们UI的Canvas父对象 方便以后外部可能会使用它
  29. public RectTransform canvas;
  30. public UIManager()
  31. {
  32. //创建Canvas 让其过场景的时候 不被移除
  33. GameObject obj = ResMgr.GetInstance().Load<GameObject>("UI/Canvas");
  34. canvas = obj.transform as RectTransform;
  35. GameObject.DontDestroyOnLoad(obj);
  36. //找到各层
  37. bot = canvas.Find("Bot");
  38. mid = canvas.Find("Mid");
  39. top = canvas.Find("Top");
  40. system = canvas.Find("System");
  41. //创建EventSystem 让其过场景的时候 不被移除
  42. obj = ResMgr.GetInstance().Load<GameObject>("UI/EventSystem");
  43. GameObject.DontDestroyOnLoad(obj);
  44. }
  45. /// <summary>
  46. /// 通过层级枚举 得到对应层级的父对象
  47. /// </summary>
  48. /// <param name="layer"></param>
  49. /// <returns></returns>
  50. public Transform GetLayerFather(E_UI_Layer layer)
  51. {
  52. switch (layer)
  53. {
  54. case E_UI_Layer.Bot:
  55. return this.bot;
  56. case E_UI_Layer.Mid:
  57. return this.mid;
  58. case E_UI_Layer.Top:
  59. return this.top;
  60. case E_UI_Layer.System:
  61. return this.system;
  62. }
  63. return null;
  64. }
  65. /// <summary>
  66. /// 显示面板
  67. /// </summary>
  68. /// <typeparam name="T">面板脚本类型</typeparam>
  69. /// <param name="panelName">面板名</param>
  70. /// <param name="layer">显示在哪一层</param>
  71. /// <param name="callBack">当面板预设体创建成功后 你想做的事</param>
  72. public void ShowPanel<T>(string panelName, E_UI_Layer layer = E_UI_Layer.Mid, UnityAction<T> callBack = null) where T : BasePanel
  73. {
  74. if (panelDic.ContainsKey(panelName))
  75. {
  76. panelDic[panelName].ShowMe();
  77. // 处理面板创建完成后的逻辑
  78. if (callBack != null)
  79. callBack(panelDic[panelName] as T);
  80. //避免面板重复加载 如果存在该面板 即直接显示 调用回调函数后 直接return 不再处理后面的异步加载逻辑
  81. return;
  82. }
  83. ResMgr.GetInstance().LoadAsync<GameObject>("UI/" + panelName, (obj) =>
  84. {
  85. //把他作为 Canvas的子对象
  86. //并且 要设置它的相对位置
  87. //找到父对象 你到底显示在哪一层
  88. Transform father = bot;
  89. switch (layer)
  90. {
  91. case E_UI_Layer.Mid:
  92. father = mid;
  93. break;
  94. case E_UI_Layer.Top:
  95. father = top;
  96. break;
  97. case E_UI_Layer.System:
  98. father = system;
  99. break;
  100. }
  101. //设置父对象 设置相对位置和大小
  102. obj.transform.SetParent(father);
  103. obj.transform.localPosition = Vector3.zero;
  104. obj.transform.localScale = Vector3.one;
  105. (obj.transform as RectTransform).offsetMax = Vector2.zero;
  106. (obj.transform as RectTransform).offsetMin = Vector2.zero;
  107. //得到预设体身上的面板脚本
  108. T panel = obj.GetComponent<T>();
  109. // 处理面板创建完成后的逻辑
  110. if (callBack != null)
  111. callBack(panel);
  112. panel.ShowMe();
  113. //把面板存起来
  114. panelDic.Add(panelName, panel);
  115. });
  116. }
  117. /// <summary>
  118. /// 隐藏面板
  119. /// </summary>
  120. /// <param name="panelName"></param>
  121. public void HidePanel(string panelName)
  122. {
  123. if (panelDic.ContainsKey(panelName))
  124. {
  125. panelDic[panelName].HideMe();
  126. GameObject.Destroy(panelDic[panelName].gameObject);
  127. panelDic.Remove(panelName);
  128. }
  129. }
  130. /// <summary>
  131. /// 得到某一个已经显示的面板 方便外部使用
  132. /// </summary>
  133. public T GetPanel<T>(string name) where T : BasePanel
  134. {
  135. if (panelDic.ContainsKey(name))
  136. return panelDic[name] as T;
  137. return null;
  138. }
  139. /// <summary>
  140. /// 给控件添加自定义事件监听
  141. /// </summary>
  142. /// <param name="control">控件对象</param>
  143. /// <param name="type">事件类型</param>
  144. /// <param name="callBack">事件的响应函数</param>
  145. public static void AddCustomEventListener(UIBehaviour control, EventTriggerType type, UnityAction<BaseEventData> callBack)
  146. {
  147. EventTrigger trigger = control.GetComponent<EventTrigger>();
  148. if (trigger == null)
  149. trigger = control.gameObject.AddComponent<EventTrigger>();
  150. EventTrigger.Entry entry = new EventTrigger.Entry();
  151. entry.eventID = type;
  152. entry.callback.AddListener(callBack);
  153. trigger.triggers.Add(entry);
  154. }
  155. }