【Unity UGUI】UGUI适配
基本完成UGUI适配功能
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 32 private Vector2 m_OlPos; 33 34 private RectTransform mParentCanvesRT; 35 36 [Header("节点自适应")] 37 public SafeAreaType m_SafeAreaType; 38 39 [HideInInspector] public RawImage rawImage; 40 41 ScreenOrientation m_LastScreenOrientation; 42 43 bool invokeRefreshFrame = true; 44 45 Vector2 lastCanvasSize; 46 int lastScreenWidth; 47 int lastScreenHeight; 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) 55 { 56 RT = GetComponent<RectTransform>(); 57 if (RT == null) return; 58 m_OlPos = RT.anchoredPosition; 59 } 60 switch (m_SafeAreaType) 61 { 62 case SafeAreaType.自适应尺寸: 63 break; 64 case SafeAreaType.全屏显示: 65 break; 66 case SafeAreaType.RawImg自适应等比缩放: 67 if (rawImage == null) rawImage = GetComponent<RawImage>(); 68 if (rawImage == null) return; 69 if (Application.isPlaying) 70 { 71 Debug.Assert(RT.anchorMax.x == RT.anchorMin.x && RT.anchorMax.x == RT.pivot.x, this); 72 Debug.Assert(RT.anchorMax.y == RT.anchorMin.y && RT.anchorMax.y == RT.pivot.y, this); 73 } 74 break; 75 default: 76 break; 77 } 78 AutoSetSafeArea(); 79 Canvas.preWillRenderCanvases += Canvas_preWillRenderCanvases; 80 } 81 82 private void Canvas_preWillRenderCanvases() 83 { 84 if (!lastCanvasSize.Equals(mParentCanvesRT.sizeDelta)) 85 { 86 lastCanvasSize = mParentCanvesRT.sizeDelta; 87 invokeRefreshFrame = true; 88 } 89 /** 90 * 渲染顺序为: 91 * 1.当前帧:设备发生更改屏幕旋转事件,修改了Screen.orientation值 92 * 2.下一帧:CanvasScaler在Canvas.preWillRenderCanvases 事件里修改Canvas适配sizeDelta 93 * preWillRenderCanvases 在即将开始 Canvas 渲染前调用的事件。 94 * 95 * 所以在检测到屏幕旋转事件后,在下一次preWillRenderCanvases事件中进行适配计算 96 */ 97 if (invokeRefreshFrame) 98 { 99 invokeRefreshFrame = false; 100 AutoSetSafeArea(); 101 } 102 if (!Screen.orientation.Equals(m_LastScreenOrientation)) 103 { 104 invokeRefreshFrame = true; 105 m_LastScreenOrientation = Screen.orientation; 106 } 107 } 108 109 void OnDisable() 110 { 111 Canvas.preWillRenderCanvases -= Canvas_preWillRenderCanvases; 112 } 113 void AutoSetSafeArea() 114 { 115 float offsetTop = Screen.safeArea.yMin / Screen.currentResolution.height; 116 float offsetBottom = Screen.safeArea.yMax / Screen.currentResolution.height; 117 float offsetLeft = Screen.safeArea.xMin / Screen.currentResolution.width; 118 float offsetRight = Screen.safeArea.xMax / Screen.currentResolution.width; 119 120 121 switch (m_SafeAreaType) 122 { 123 case SafeAreaType.自适应尺寸: 124 //安全区域偏移量 125 RT.anchorMin = new Vector2(offsetLeft, offsetTop); 126 RT.anchorMax = new Vector2(offsetRight, offsetBottom); 127 break; 128 case SafeAreaType.全屏显示: 129 //还原安全区偏移量 130 RT.anchorMin = RT.anchorMax = new Vector2(0.5f, 0.5f); 131 RT.sizeDelta = mParentCanvesRT.sizeDelta; 132 133 Vector2 SafeAreaPanelOffset; 134 SafeAreaPanelOffset.x = ((Screen.currentResolution.width - Screen.safeArea.xMax) * 0.5f - Screen.safeArea.xMin * 0.5f) * mParentCanvesRT.sizeDelta.x / Screen.currentResolution.width; 135 SafeAreaPanelOffset.y = ((Screen.currentResolution.height - Screen.safeArea.yMax) * 0.5f - Screen.safeArea.yMin * 0.5f) * mParentCanvesRT.sizeDelta.y / Screen.currentResolution.height; 136 137 RT.anchoredPosition = SafeAreaPanelOffset; 138 break; 139 case SafeAreaType.RawImg自适应等比缩放: 140 Vector2 textureSize, rawRtSize; 141 textureSize = rawRtSize = rawImage.texture == null ? new Vector2(1667, 1024) : new Vector2(rawImage.texture.width, rawImage.texture.height); 142 if (mParentCanvesRT.sizeDelta.x / mParentCanvesRT.sizeDelta.y < textureSize.x / textureSize.y) 143 { 144 rawRtSize.y = mParentCanvesRT.sizeDelta.y; 145 rawRtSize.x = mParentCanvesRT.sizeDelta.y * textureSize.x / textureSize.y; 146 } 147 else 148 { 149 rawRtSize.x = mParentCanvesRT.sizeDelta.x; 150 rawRtSize.y = mParentCanvesRT.sizeDelta.x * textureSize.y / textureSize.x; 151 } 152 153 SafeAreaPanelOffset.x = ((Screen.currentResolution.width - Screen.safeArea.xMax) * RT.anchorMax.x - Screen.safeArea.xMin * (1 - RT.anchorMin.x)) * mParentCanvesRT.sizeDelta.x / Screen.currentResolution.width; 154 SafeAreaPanelOffset.y = ((Screen.currentResolution.height - Screen.safeArea.yMax) * RT.anchorMax.y - Screen.safeArea.yMin * (1 - RT.anchorMax.y)) * mParentCanvesRT.sizeDelta.y / Screen.currentResolution.height; 155 156 RT.sizeDelta = rawRtSize; 157 RT.anchoredPosition = m_OlPos + SafeAreaPanelOffset; 158 break; 159 default: 160 break; 161 } 162 163 } 164 165 //#if UNITY_EDITOR || EDITORMODE 166 // //public bool ShowGUI; 167 // //private void OnGUI() 168 // //{ 169 // // if (!ShowGUI) 170 // // { 171 // // return; 172 // // } 173 // // GUIStyle gUIStyle = new GUIStyle(); 174 // // gUIStyle.normal.textColor = Color.blue; 175 // // gUIStyle.fontSize = 20; 176 // // GUILayout.Space(100); 177 // // GUILayout.Label($"offsetTop: {offsetTop}", gUIStyle); 178 // // GUILayout.Label($"offsetBottom: {offsetBottom}", gUIStyle); 179 // // GUILayout.Label($"offsetLeft: {offsetLeft}", gUIStyle); 180 // // GUILayout.Label($"offsetRight: {offsetRight}", gUIStyle); 181 // // GUILayout.Label($"Screen.safeArea.xMin: {Screen.safeArea.xMin}", gUIStyle); 182 // // GUILayout.Label($"Screen.safeArea.xMax: {Screen.safeArea.xMax}", gUIStyle); 183 // // GUILayout.Label($"Screen.safeArea.yMax: {Screen.safeArea.yMax}", gUIStyle); 184 // // GUILayout.Label($"Screen.safeArea.yMin: {Screen.safeArea.yMin}", gUIStyle); 185 // // GUILayout.Label($"Screen.currentResolution.width: {Screen.currentResolution.width}", gUIStyle); 186 // // GUILayout.Label($"Screen.currentResolution.height: {Screen.currentResolution.height}", gUIStyle); 187 // // GUILayout.Label($"SafeAreaPanelOffset: ({SafeAreaPanelOffset.x},{SafeAreaPanelOffset.y})", gUIStyle); 188 // // GUILayout.Label($"Screen.orientation: {Screen.orientation}", gUIStyle); 189 // // GUILayout.Label($"m_LastScreenOrientation: {m_LastScreenOrientation}", gUIStyle); 190 191 // //} 192 //#endif 193 194 195 }
*Screen.safeArea不支持Android8.0及以下的信息获取,如果需要单独添加设备适配配置
当然也可以跟我一下 忽略。。。
针对折叠屏的适配,暂时可以在Android层添加onConfigurationChanged监听
然后在Unity里面调用一下适配刷新即可
折叠屏的适配-这里同样可以
1 if (!lastCanvasSize.Equals(mParentCanvesRT.sizeDelta)) 2 { 3 lastCanvasSize = mParentCanvesRT.sizeDelta; 4 invokeRefreshFrame = true; 5 }