ZMUIL2——遮罩系统
遮罩系统要做的工作
开启单遮模式时,每当调用UIModule
来控制UI窗口显示隐藏时,
UIModule
的遮罩系统都要计算显示的窗口中哪个窗口需要开启遮罩,并隐藏其他窗口的遮罩,以达到单遮的效果
UI配置文件可设定是否开启单遮模式
- 单遮模式:无论打开多少界面,遮罩只有一层。
- 叠遮模式:即每一个界面都有一层遮罩,打开的界面越多,遮罩就越黑。
UIModule的遮罩系统相关
配置文件
首先需要配置文件来控制遮罩系统的开关,使用继承ScriptableObject
的单例配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| using UnityEngine;
[CreateAssetMenu(fileName = "UISetting", menuName = "UISetting", order = 0)] public class UISetting : ScriptableObject { private static UISetting instance; public static UISetting Instance { get { if (instance == null) { instance = Resources.Load<UISetting>("UISetting"); } return instance; } }
public bool SINGMASK_SYSTEM; }
|
右键创建UISetting配置文件,即可在选择是否开启单遮模式
UI对象结构
为了便于UIModule
管理各个窗口的遮罩,窗口对象的基本结构规定为:
其中,UIMask对象为一个覆盖全屏的黑色Image,黑色Image的透明度由CanvasGroup决定
简单来说,一个Window模板对象会包括UIMask对象作为背景遮罩,UIContent作为所有UI控件的父对象
值得一提的是:
- 使用这里的UIMask遮罩对象会使用Canvas Group进行控制遮罩的显示与隐藏
不使用SetActive
设置的原因是,使用它会造成UI对象重绘,浪费性能
- 这里创建UIContent作为UI控件父节点的原因是,便于缩放动画的制作,
可以通过缩放UIContent来制作缩放动画,同时也避免UIMask也跟着缩放。
遮罩系统思路及其实现
遮罩系统主要在UI窗口显示隐藏时工作,而UIModule
负责窗口显隐的执行,因此遮罩系统主要在UIModule
内实现
首先需要在WindowBase
内实现对UIMask显隐的控制,并对UIModule
提供控制窗口UIMask显隐的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class WindowBase : WindowBehaviour {
private CanvasGroup mUIMask; protected Transform mUIContent;
private void InitializeBaseComponent() { mUIMask = transform.Find("UIMask").GetComponent<CanvasGroup>(); mUIContent = transform.Find("UIContent").transform; }
#region 生命周期函数的声明 public override void OnAwake() { base.OnAwake(); InitializeBaseComponent(); }
#endregion
public override void SetVisible(bool isVisible) { }
public void SetMaskVisible(bool isVisible) { if (!UISetting.Instance.SINGMASK_SYSTEM) return; mUIMask.alpha = isVisible ? 1f : 0f; }
#region 事件管理方法 #endregion }
|
接下来需要在UIModule
实现一套调节UI遮罩的算法,原理较复杂,使用伪代码阐述思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 目的:通过调用WindowBase类的SetMaskVisible方法开启唯一符合条件的窗口的遮罩,关闭所有不符合条件的窗口的遮罩,实现单遮效果 符合开启遮罩的窗口的条件:窗口的Canvas的sortingOrder最大时,位于兄弟窗口排序最靠后的窗口
private void 设置窗口遮罩() { if 未开启单遮模式 return var 要开启遮罩的窗口 = null for 遍历所有的可见的窗口 if 遍历到的窗口不为空且对应的UI对象也不为空 关闭当前循环到的窗口的遮罩 if 要开启遮罩的窗口 == null 要开启遮罩的窗口 = 当前循环到的窗口 else if 要开启遮罩的窗口的渲染层级 < 当前循环到的窗口的渲染层级 要开启遮罩的窗口 = 当前循环到的窗口 else if 要开启遮罩的窗口的渲染层级 == 当前循环到的窗口的渲染层级 && 要开启遮罩的窗口比当前循环到的窗口在同层级排序中更靠下 要开启遮罩的窗口 = 当前循环到的窗口 if 要开启遮罩的窗口不为空 开启唯一符合条件的窗口的遮罩 }
|
SetWindowMaskVisible()
会在UIModule
的弹出窗口,隐藏窗口,销毁窗口里调用,达到每次显示隐藏面板时都会计算哪个面板需要开启遮罩,实现单遮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
#region 控制遮罩相关
private void SetWindowMaskVisible() { if (!UISetting.Instance.SINGMASK_SYSTEM) return; WindowBase maxOrderWindowBase = null; int maxOrder = 0; int maxIndex = 0; for (int i = 0; i < mVisibleWindowList.Count; i++) { WindowBase window = mVisibleWindowList[i]; if (window != null && window.gameObject != null) { window.SetMaskVisible(false); if (maxOrderWindowBase == null) { maxOrderWindowBase = window; maxOrder = window.Canvas.sortingOrder; maxIndex = window.transform.GetSiblingIndex(); } else { if (maxOrder < window.Canvas.sortingOrder) { maxOrderWindowBase = window; maxOrder = window.Canvas.sortingOrder; } else if (maxOrder == window.Canvas.sortingOrder && maxIndex < window.transform.GetSiblingIndex()) { maxOrderWindowBase = window; maxIndex = window.transform.GetSiblingIndex(); } } } } maxOrderWindowBase?.SetMaskVisible(true); } #endregion
|