【Unity UGUI】UGUI适配

发布时间 2023-11-15 18:03:30作者: lovewaits
  1 /*=================================================
  2 *FileName:      SafeAreaPanel.cs 
  3 *Author:        None 
  4 *UnityVersion:  2021.3.20f1 
  5 *Date:          2023-07-20 16:11 
  6 *Description:   UI适配组件
  7 *History:       
  8 *------------------------------------------------
  9 *2023年11月15日17:35:12
 10 *修复获取安全区尺寸的正确数据
 11 *重构适配数据的计算逻辑
 12 *重构全屏显示
 13 *新增RawImg自适应等比缩放(合并脚本)
 14 *重构后适配可根据具体上下左右安全区范围做显示
 15 =================================================*/
 16 using System;
 17 using UnityEngine;
 18 using UnityEngine.UI;
 19 
 20 public class SafeAreaPanel : MonoBehaviour
 21 {
 22     public enum SafeAreaType
 23     {
 24         自适应尺寸,
 25         全屏显示,
 26         /// <summary> 要求所有适配锚点x/y保持一致 </summary>
 27         RawImg自适应等比缩放,
 28     }
 29 
 30     RectTransform RT = null;
 31     private Vector2 m_OlPos;
 32     private RectTransform mParentCanvesRT;
 33     [Header("节点自适应")]
 34     public SafeAreaType m_SafeAreaType;
 35     /// <summary> 屏幕适配UI中心点偏移(ms) </summary>
 36     private Vector2 SafeAreaPanelOffset;
 37 
 38     [HideInInspector] public RawImage rawImage;
 39 
 40     float offsetTop;
 41     float offsetBottom;
 42     float offsetLeft;
 43     float offsetRight;
 44 
 45     ScreenOrientation m_LastScreenOrientation;
 46     bool invokeRefreshFrame = true;
 47     Vector2 lastCanvasSize;
 48 
 49     void OnEnable()
 50     {
 51         if (this == null || this.gameObject == null) return;
 52         if (mParentCanvesRT == null) mParentCanvesRT = GetComponentInParent<CanvasScaler>()?.GetComponent<RectTransform>();
 53         if (mParentCanvesRT == null) return;
 54         if (RT == null) RT = GetComponent<RectTransform>();
 55         if (RT == null) return;
 56         m_OlPos = RT.anchoredPosition;
 57         switch (m_SafeAreaType)
 58         {
 59             case SafeAreaType.自适应尺寸:
 60                 break;
 61             case SafeAreaType.全屏显示:
 62                 break;
 63             case SafeAreaType.RawImg自适应等比缩放:
 64                 if (rawImage == null) rawImage = GetComponent<RawImage>();
 65                 if (rawImage == null) return;
 66                 if (Application.isPlaying)
 67                 {
 68                     Debug.Assert(RT.anchorMax.x == RT.anchorMin.x && RT.anchorMax.x == RT.pivot.x, this);
 69                     Debug.Assert(RT.anchorMax.y == RT.anchorMin.y && RT.anchorMax.y == RT.pivot.y, this);
 70                 }
 71                 break;
 72             default:
 73                 break;
 74         }
 75         AutoSetSafeArea();
 76         Canvas.preWillRenderCanvases += Canvas_preWillRenderCanvases;
 77     }
 78 
 79     private void Canvas_preWillRenderCanvases()
 80     {
 81         if (!lastCanvasSize.Equals(mParentCanvesRT.sizeDelta))
 82         {
 83             lastCanvasSize = mParentCanvesRT.sizeDelta;
 84             invokeRefreshFrame = true;
 85         }
 86         /**
 87          * 渲染顺序为:
 88          *  1.当前帧:设备发生更改屏幕旋转事件,修改了Screen.orientation值
 89          *  2.下一帧:CanvasScaler在Canvas.preWillRenderCanvases 事件里修改Canvas适配sizeDelta
 90          *  preWillRenderCanvases    在即将开始 Canvas 渲染前调用的事件。
 91          *  
 92          *  所以在检测到屏幕旋转事件后,在下一次preWillRenderCanvases事件中进行适配计算
 93          */
 94         if (invokeRefreshFrame)
 95         {
 96             invokeRefreshFrame = false;
 97             AutoSetSafeArea();
 98         }
 99         if (!Screen.orientation.Equals(m_LastScreenOrientation))
100         {
101             invokeRefreshFrame = true;
102             m_LastScreenOrientation = Screen.orientation;
103         }
104     }
105 
106     void OnDisable()
107     {
108         Canvas.preWillRenderCanvases -= Canvas_preWillRenderCanvases;
109     }
110     void AutoSetSafeArea()
111     {
112         offsetTop = Screen.safeArea.yMin / Screen.currentResolution.height;
113         offsetBottom = Screen.safeArea.yMax / Screen.currentResolution.height;
114         offsetLeft = Screen.safeArea.xMin / Screen.currentResolution.width;
115         offsetRight = Screen.safeArea.xMax / Screen.currentResolution.width;
116 
117 
118         switch (m_SafeAreaType)
119         {
120             case SafeAreaType.自适应尺寸:
121                 //安全区域偏移量
122                 RT.anchorMin = new Vector2(offsetLeft, offsetTop);
123                 RT.anchorMax = new Vector2(offsetRight, offsetBottom);
124                 break;
125             case SafeAreaType.全屏显示:
126                 //还原安全区偏移量
127                 RT.anchorMin = RT.anchorMax = new Vector2(0.5f, 0.5f);
128                 RT.sizeDelta = new Vector2(Screen.currentResolution.width, Screen.currentResolution.height);
129 
130                 SafeAreaPanelOffset.x = ((Screen.currentResolution.width - Screen.safeArea.xMax) * 0.5f - Screen.safeArea.xMin * 0.5f) * mParentCanvesRT.sizeDelta.x / Screen.currentResolution.width;
131                 SafeAreaPanelOffset.y = ((Screen.currentResolution.height - Screen.safeArea.yMax) * 0.5f - Screen.safeArea.yMin * 0.5f) * mParentCanvesRT.sizeDelta.y / Screen.currentResolution.height;
132 
133                 RT.anchoredPosition = SafeAreaPanelOffset;
134                 break;
135             case SafeAreaType.RawImg自适应等比缩放:
136                 Vector2 textureSize, rawRtSize;
137                 textureSize = rawRtSize = rawImage.texture == null ? new Vector2(1667, 1024) : new Vector2(rawImage.texture.width, rawImage.texture.height);
138                 if (mParentCanvesRT.sizeDelta.x / mParentCanvesRT.sizeDelta.y < textureSize.x / textureSize.y)
139                 {
140                     rawRtSize.y = mParentCanvesRT.sizeDelta.y;
141                     rawRtSize.x = mParentCanvesRT.sizeDelta.y * textureSize.x / textureSize.y;
142                 }
143                 else
144                 {
145                     rawRtSize.x = mParentCanvesRT.sizeDelta.x;
146                     rawRtSize.y = mParentCanvesRT.sizeDelta.x * textureSize.y / textureSize.x;
147                 }
148 
149                 SafeAreaPanelOffset.x = ((Screen.currentResolution.width - Screen.safeArea.xMax) * RT.anchorMax.x - Screen.safeArea.xMin * (1 - RT.anchorMin.x)) * mParentCanvesRT.sizeDelta.x / Screen.currentResolution.width;
150                 SafeAreaPanelOffset.y = ((Screen.currentResolution.height - Screen.safeArea.yMax) * RT.anchorMax.y - Screen.safeArea.yMin * (1 - RT.anchorMax.y)) * mParentCanvesRT.sizeDelta.y / Screen.currentResolution.height;
151 
152                 RT.sizeDelta = rawRtSize;
153                 RT.anchoredPosition = m_OlPos + SafeAreaPanelOffset;
154                 break;
155             default:
156                 break;
157         }
158 
159     }
160 
161     //#if UNITY_EDITOR || EDITORMODE
162     //    //public bool ShowGUI;
163     //    //private void OnGUI()
164     //    //{
165     //    //    if (!ShowGUI)
166     //    //    {
167     //    //        return;
168     //    //    }
169     //    //    GUIStyle gUIStyle = new GUIStyle();
170     //    //    gUIStyle.normal.textColor = Color.blue;
171     //    //    gUIStyle.fontSize = 20;
172     //    //    GUILayout.Space(100);
173     //    //    GUILayout.Label($"offsetTop: {offsetTop}", gUIStyle);
174     //    //    GUILayout.Label($"offsetBottom: {offsetBottom}", gUIStyle);
175     //    //    GUILayout.Label($"offsetLeft: {offsetLeft}", gUIStyle);
176     //    //    GUILayout.Label($"offsetRight: {offsetRight}", gUIStyle);
177     //    //    GUILayout.Label($"Screen.safeArea.xMin: {Screen.safeArea.xMin}", gUIStyle);
178     //    //    GUILayout.Label($"Screen.safeArea.xMax: {Screen.safeArea.xMax}", gUIStyle);
179     //    //    GUILayout.Label($"Screen.safeArea.yMax: {Screen.safeArea.yMax}", gUIStyle);
180     //    //    GUILayout.Label($"Screen.safeArea.yMin: {Screen.safeArea.yMin}", gUIStyle);
181     //    //    GUILayout.Label($"Screen.currentResolution.width: {Screen.currentResolution.width}", gUIStyle);
182     //    //    GUILayout.Label($"Screen.currentResolution.height: {Screen.currentResolution.height}", gUIStyle);
183     //    //    GUILayout.Label($"SafeAreaPanelOffset: ({SafeAreaPanelOffset.x},{SafeAreaPanelOffset.y})", gUIStyle);
184     //    //    GUILayout.Label($"Screen.orientation: {Screen.orientation}", gUIStyle);
185     //    //    GUILayout.Label($"m_LastScreenOrientation: {m_LastScreenOrientation}", gUIStyle);
186 
187     //    //}
188     //#endif
189 
190 
191 }
View Code

基本完成UGUI适配功能
*Screen.safeArea不支持Android8.0及以下的信息获取,如果需要单独添加设备适配配置
当然也可以跟我一下 忽略。。。
针对折叠屏的适配,暂时可以在Android层添加onConfigurationChanged监听
然后在Unity里面调用一下适配刷新即可