宽高比是显示屏宽度和高度之间的比率。宽高比用于保持显示屏的比例。例如,如果宽高比为 4:3,则显示器的宽度与高度比例为每 4 像素宽度对应 3 像素高度。如果宽高比为 16:9,则显示器的宽度与高度比例为每 16 像素宽度对应 9 像素高度。
此示例创建了一个自定义控件,可保持其子元素的指定宽高比。出于演示目的,自定义控件会根据显示屏比例添加内边距:如果显示屏比例较宽,则添加左右内边距;如果显示屏比例较高,则添加上下内边距,从而使“中心”内容适配宽高比。
您可以在此 GitHub 代码仓库中找到此示例创建的完整文件。
本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发者。在开始之前,请熟悉以下内容:
创建一个继承自 VisualElement 的 C# 类,该类有两个属性:width 和 height。width 和 height 属性用于计算宽高比。
使用任何模板创建 Unity 项目。
创建名为 AspectRatio.cs 的 C# 脚本,其中包含以下内容:
using UnityEngine;
using UnityEngine.UIElements;
// Custom element that lays out its contents following a specific aspect ratio.
[UxmlElement]
public partial class AspectRatioElement : VisualElement
{
// The ratio of width.
[UxmlAttribute("width")]
public int RatioWidth
{
get => _ratioWidth;
set
{
_ratioWidth = value;
UpdateAspect();
}
}
// The ratio of height.
[UxmlAttribute("height")]
public int RatioHeight
{
get => _ratioHeight;
set
{
_ratioHeight = value;
UpdateAspect();
}
}
// Padding elements to keep the aspect ratio.
private int _ratioWidth = 16;
private int _ratioHeight = 9;
public AspectRatioElement()
{
// Update the padding elements when the geometry changes.
RegisterCallback<GeometryChangedEvent>(UpdateAspectAfterEvent);
// Update the padding elements when the element is attached to a panel.
RegisterCallback<AttachToPanelEvent>(UpdateAspectAfterEvent);
}
static void UpdateAspectAfterEvent(EventBase evt)
{
var element = evt.target as AspectRatioElement;
element?.UpdateAspect();
}
private void ClearPadding()
{
style.paddingLeft = 0;
style.paddingRight = 0;
style.paddingBottom = 0;
style.paddingTop = 0;
}
// Update the padding.
private void UpdateAspect()
{
var designRatio = (float)RatioWidth / RatioHeight;
var currRatio = resolvedStyle.width / resolvedStyle.height;
var diff = currRatio - designRatio;
if (RatioWidth <= 0.0f || RatioHeight <= 0.0f)
{
ClearPadding();
Debug.LogError($"[AspectRatio] Invalid width:{RatioWidth} or height:{RatioHeight}");
return;
}
if (float.IsNaN(resolvedStyle.width) || float.IsNaN(resolvedStyle.height))
{
return;
}
if (diff > 0.01f)
{
var w = (resolvedStyle.width - (resolvedStyle.height * designRatio)) * 0.5f;
style.paddingLeft = w;
style.paddingRight = w;
style.paddingTop = 0;
style.paddingBottom = 0;
}
else if (diff < -0.01f)
{
var h = (resolvedStyle.height - (resolvedStyle.width * (1/designRatio))) * 0.5f;
style.paddingLeft= 0;
style.paddingRight = 0;
style.paddingTop = h;
style.paddingBottom = h;
}
else
{
ClearPadding();
}
}
}
创建一个使用自定义控件的自定义 Editor 窗口。测试自定义控件,查看在更改宽高比时它的表现。
创建名为 AspectRatioDemo.cs 的 C# 脚本,其中包含以下内容:
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class AspectRatioDemo : EditorWindow
{
[MenuItem("Test/AspectRatioDemo")]
public static void ShowExample()
{
AspectRatioDemo wnd = GetWindow<AspectRatioDemo>();
wnd.titleContent = new GUIContent("AspectRatioDemo");
}
public void CreateGUI()
{
// Each editor window contains a root VisualElement object.
VisualElement root = rootVisualElement;
var aspectRatio = new AspectRatioElement();
aspectRatio.style.flexGrow = 1;
var widthField = new IntegerField() { value = aspectRatio.RatioWidth, label = "W"};
var heightField = new IntegerField() { value = aspectRatio.RatioHeight, label = "H" };
root.Add(widthField);
root.Add(heightField);
root.Add(aspectRatio);
var contents = new VisualElement();
aspectRatio.Add(contents);
aspectRatio.style.backgroundColor = Color.black;
contents.style.backgroundColor = Color.green;
widthField.RegisterValueChangedCallback((evt) =>aspectRatio.RatioWidth = evt.newValue);
heightField.RegisterValueChangedCallback((evt) => aspectRatio.RatioHeight = evt.newValue);
contents.style.width = new Length(100, LengthUnit.Percent);
contents.style.height = new Length(100, LengthUnit.Percent);
contents.RegisterCallback<GeometryChangedEvent>((evt) =>
{
Debug.Log($"Content ratio: {evt.newRect.width} x {evt.newRect.height} : {evt.newRect.width/evt.newRect.height}");
});
}
}
从菜单中选择测试 (Test) > 宽高比演示 (Aspect Ratio Demo)。
将宽高比更改为不同的值。该自定义控件会根据 Editor 窗口的大小,在左右两侧或上下两侧添加内边距。