> 技术文档 > Unity 2D动态UI:适配鸿蒙不同屏幕尺寸的按钮/文本布局实践_unity的ui布局位置代码getscreenheight

Unity 2D动态UI:适配鸿蒙不同屏幕尺寸的按钮/文本布局实践_unity的ui布局位置代码getscreenheight


引言

鸿蒙系统覆盖手机(16:9/18:9)、平板(4:3/16:10)、车机(长条形/异形屏)等多尺寸设备,Unity 2D UI若采用固定像素布局,易出现按钮错位、文本溢出或元素重叠等问题。本文将结合鸿蒙屏幕特性与Unity UGUI系统,设计一套​​动态适配方案​​,通过代码实现按钮、文本等核心元素的自动缩放与布局调整。


一、鸿蒙屏幕适配的核心挑战

鸿蒙设备的屏幕差异主要体现在三个方面,需针对性解决:

1. 屏幕比例多样性

手机常见16:9(如1080×1920),平板多为16:10(如2560×1600),车机可能采用更长比例(如21:9或自定义异形屏)。固定宽高比的UI布局无法适配所有设备。

2. 分辨率跨度大

从低分辨率手机(720×1280)到高分辨率平板(3840×2160),直接使用像素(Px)定位会导致元素大小在不同设备上差异显著(如100px在小屏手机可能过大,在大屏平板可能过小)。

3. 文本可读性要求

鸿蒙设备用户可能在不同距离使用(如手机贴近面部,车机远距离观看),文本需根据屏幕尺寸动态调整字体大小,确保清晰可读。


二、动态UI布局设计思路

核心目标是让UI元素​​“基于屏幕尺寸自动调整”​​,而非依赖固定数值。方案包含以下关键步骤:

1. 基于比例的Canvas缩放

使用Canvas Scaler组件,设置UI Scale ModeScale With Screen Size,以目标分辨率(如1920×1080)为基准,通过Reference ResolutionScreen Match Mode(匹配宽度/高度/混合)实现全局缩放。

2. 动态布局区域划分

将屏幕划分为“安全区域”(如中间80%区域),避免元素被屏幕圆角、刘海遮挡;使用Horizontal/Vertical Layout GroupGrid Layout Group管理子元素,结合Content Size Fitter实现自适应排列。

3. 百分比定位与动态计算

通过代码获取屏幕宽高比(Screen.width/Screen.height),动态计算按钮位置、文本字体大小,确保元素在不同比例屏幕上的相对位置一致。

4. 文本自适应优化

使用TextMeshPro组件替代原生Text,支持自动换行、字体大小自适应(通过Best Fit功能或代码动态调整)。


三、代码实现:动态按钮与文本布局

1. 基础Canvas配置(Unity编辑器设置)

首先创建Canvas并配置适配参数:

  • 渲染模式:Screen Space - Overlay(覆盖屏幕,适合2D UI)。
  • 添加Canvas Scaler组件:
    • UI Scale ModeScale With Screen Size
    • Reference Resolution → 设计基准分辨率(如1920×1080)。
    • Screen Match ModeMatch Width or Height(根据设备选择匹配宽度或高度,或通过代码动态调整)。

2. 动态布局管理器(C#脚本)

创建UILayoutManager单例,负责监听屏幕尺寸变化并调整UI元素:

// UILayoutManager.csusing UnityEngine;using UnityEngine.UI;using TMPro;public class UILayoutManager : MonoBehaviour { public static UILayoutManager Instance { get; private set; } [Header(\"基准配置\")] [Tooltip(\"设计基准的屏幕宽高比(如1920x1080对应16:9)\")] public Vector2 designAspectRatio = new Vector2(1920f, 1080f); [Tooltip(\"安全区域边距(屏幕边缘预留空间)\")] public float safeAreaMargin = 0.05f; // 5%边距 [Header(\"按钮配置\")] public Button[] dynamicButtons; // 需要动态调整的按钮数组 public float buttonMinWidth = 200f; // 按钮最小宽度(基准分辨率下的像素) public float buttonHeight = 60f; // 按钮固定高度(可根据需求调整) [Header(\"文本配置\")] public TextMeshProUGUI[] dynamicTexts; // 需要动态调整的文本数组 public float minFontSize = 14f; // 最小字体大小 public float maxFontSize = 24f; // 最大字体大小 private void Awake() { if (Instance == null) Instance = this; else Destroy(gameObject); } private void Start() { AdjustLayout(); // 监听屏幕尺寸变化(鸿蒙设备旋转或分辨率切换时触发) Screen.onResolutionChanged += OnResolutionChanged; } private void OnDestroy() { Screen.onResolutionChanged -= OnResolutionChanged; } // 屏幕尺寸变化回调 private void OnResolutionChanged(Vector2Int resolution) { AdjustLayout(); } // 核心布局调整逻辑 public void AdjustLayout() { // 1. 计算当前屏幕宽高比与基准宽高比的匹配度 float currentAspectRatio = (float)Screen.width / Screen.height; float aspectRatioDiff = Mathf.Abs(currentAspectRatio - designAspectRatio.x / designAspectRatio.y); // 2. 调整Canvas Scaler的匹配模式(可选:根据宽高比自动切换匹配宽度/高度) CanvasScaler canvasScaler = FindObjectOfType(); if (canvasScaler != null) { canvasScaler.matchWidthOrHeight = (currentAspectRatio > designAspectRatio.x / designAspectRatio.y)  ? 1f // 宽度主导(适合横屏设备) : 0f; // 高度主导(适合竖屏设备) } // 3. 调整按钮布局(位置+大小) AdjustButtons(); // 4. 调整文本布局(字体大小+位置) AdjustTexts(); } // 动态调整按钮位置与大小 private void AdjustButtons() { float safeWidth = Screen.width * (1 - 2 * safeAreaMargin); float safeHeight = Screen.height * (1 - 2 * safeAreaMargin); foreach (Button btn in dynamicButtons) { // 获取按钮原始大小(基准分辨率下的设计值) RectTransform rectTrans = btn.GetComponent(); Vector2 originalSize = rectTrans.sizeDelta; // 动态计算宽度(最小为buttonMinWidth,最大不超过安全区域的80%) float targetWidth = Mathf.Clamp(originalSize.x * (Screen.width / designAspectRatio.x),  buttonMinWidth, safeWidth * 0.8f); // 高度保持固定比例(或根据设计需求调整) float targetHeight = originalSize.y * (targetWidth / originalSize.x); // 更新按钮大小 rectTrans.sizeDelta = new Vector2(targetWidth, targetHeight); // 水平居中放置在安全区域底部(Y坐标为安全区域高度 - 按钮高度 - 边距) float xPos = (Screen.width - targetWidth) / 2; float yPos = safeHeight - targetHeight - (Screen.height * safeAreaMargin); rectTrans.anchoredPosition = new Vector2(xPos, yPos); } } // 动态调整文本字体大小与位置 private void AdjustTexts() { float safeWidth = Screen.width * (1 - 2 * safeAreaMargin); float safeHeight = Screen.height * (1 - 2 * safeAreaMargin); foreach (TextMeshProUGUI text in dynamicTexts) { RectTransform rectTrans = text.GetComponent(); // 文本宽度自适应(不超过安全区域的90%) float maxWidth = safeWidth * 0.9f; text.maxWidth = maxWidth; // 自动调整字体大小(使用TextMeshPro的Best Fit功能) text.autoSizeTextContainer = true; text.alignment = TextAlignmentOptions.Center; // 若需手动控制字体大小(替代Best Fit): /* float textWidth = text.preferredWidth; float textHeight = text.preferredHeight; float scale = Mathf.Min(maxWidth / textWidth, safeHeight / textHeight); text.fontSize = Mathf.RoundToInt(Mathf.Clamp(text.fontSize * scale, minFontSize, maxFontSize)); */ } }}

3. 按钮与文本的Unity编辑器配置

在Unity中创建UI元素并绑定脚本:

  1. 新建Canvas,添加UILayoutManager脚本到空物体(如命名为UILayoutRoot)。
  2. 创建按钮(Button)并添加到dynamicButtons数组:
    • 设置按钮的RectTransform锚点为Middle Center(中间居中)。
    • 添加Horizontal Layout Group(可选,用于多按钮横向排列)。
  3. 创建文本(TextMeshPro - Text (UI))并添加到dynamicTexts数组:
    • 启用Auto Size(在Inspector中勾选Auto Size Text)。
    • 设置AnchorStretch(拉伸填充父容器)。

4. 鸿蒙设备特殊处理(刘海屏/异形屏)

鸿蒙部分设备(如折叠屏、带刘海的手机)存在屏幕安全区域限制,需通过Screen.safeArea获取安全区域坐标,避免UI被遮挡:

// 在AdjustLayout方法中添加安全区域适配Rect safeArea = Screen.safeArea;Vector2Int safeSize = new Vector2Int( (int)(safeArea.width * Screen.dpi), (int)(safeArea.height * Screen.dpi));// 使用safeSize替代Screen.width/height计算布局// 示例:将按钮放置在安全区域内float safeLeft = safeArea.x * (Screen.width / Screen.currentResolution.width);float safeBottom = safeArea.y * (Screen.height / Screen.currentResolution.height);rectTrans.anchoredPosition = new Vector2(safeLeft + (safeWidth - targetWidth)/2, safeBottom + safeHeight - targetHeight - margin);

四、测试与优化建议

1. 多分辨率测试

在Unity中通过Game视图的分辨率下拉菜单模拟鸿蒙设备(如1080×1920、2560×1600、2160×1080),验证按钮是否居中、文本是否换行或缩放。

2. 真机调试

通过DevEco Studio连接鸿蒙手机/平板,使用adb logcat查看是否有布局错误日志(如文本溢出),调整buttonMinWidthmaxFontSize参数。

3. 性能优化

  • 避免在AdjustLayout中频繁调用GetComponent,可将RectTransform组件缓存。
  • 对于复杂UI(如列表),使用Recycle ListView替代多个独立按钮,减少Draw Call。

4. 动态加载布局配置

可通过JSON文件存储不同设备的布局参数(如按钮大小、文本字体),运行时根据设备型号加载对应配置,提升适配灵活性。


总结

通过Canvas Scaler全局缩放、动态计算元素位置/大小,结合代码对屏幕宽高比和分辨率的实时响应,可有效解决鸿蒙多尺寸设备的UI适配问题。核心原则是​​“相对布局优于绝对定位”​​,通过百分比、安全区域和动态计算确保UI在不同设备上的一致性与可用性。