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里面调用一下适配刷新即可
折叠屏的适配-这里同样可以
1 if (!lastCanvasSize.Equals(mParentCanvesRT.sizeDelta)) 2 { 3 lastCanvasSize = mParentCanvesRT.sizeDelta; 4 invokeRefreshFrame = true; 5 }
标签:RT,适配,Screen,Unity,currentResolution,mParentCanvesRT,UGUI,safeArea,sizeDelta From: https://www.cnblogs.com/lovewaits/p/17834443.html