unity-ui-development
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnity UI Development
Unity UI 开发
Overview
概述
Unity provides two UI systems: UGUI (the established GameObject-based system) and UI Toolkit (the newer retained-mode system inspired by web technologies). This skill covers both systems, when to use each, and implementation patterns.
Unity提供两种UI系统:UGUI(基于GameObject的成熟系统)和UI Toolkit(受Web技术启发的新型保留模式系统)。本技能涵盖这两种系统的使用场景与实现模式。
Choosing a UI System
UI系统选择
| Factor | UGUI | UI Toolkit |
|---|---|---|
| Runtime UI | Mature, full-featured | Supported (Unity 2023+) |
| Editor UI | Not supported | Primary system for editor |
| World-space UI | Excellent (World Space Canvas) | Limited |
| Animation/Tweening | DOTween, Animator, LeanTween | USS transitions, C# manipulation |
| Styling | Per-element, manual | USS stylesheets (CSS-like) |
| Performance | Draw call heavy with many canvases | Retained mode, lighter draw calls |
| Learning curve | Lower for Unity devs | Higher (web-like paradigm) |
| VR/AR | Well-supported | Limited world-space support |
Recommendation: Use UGUI for world-space UI, VR/AR, and projects needing maximum asset store compatibility. Use UI Toolkit for editor extensions, complex data-driven UIs (lists, trees), and projects on Unity 2023+.
| 因素 | UGUI | UI Toolkit |
|---|---|---|
| 运行时UI | 成熟、功能完整 | 支持(Unity 2023+) |
| 编辑器UI | 不支持 | 编辑器首选系统 |
| 世界空间UI | 表现优异(World Space Canvas) | 支持有限 |
| 动画/补间 | DOTween、Animator、LeanTween | USS过渡、C#操作 |
| 样式设置 | 逐元素手动设置 | USS样式表(类CSS) |
| 性能 | 多画布场景下Draw Call开销大 | 保留模式,Draw Call开销更低 |
| 学习曲线 | Unity开发者上手难度低 | 难度较高(类Web范式) |
| VR/AR | 支持完善 | 世界空间支持有限 |
建议: 将UGUI用于世界空间UI、VR/AR以及需要最大程度兼容资源商店的项目。将UI Toolkit用于编辑器扩展、复杂的数据驱动UI(列表、树形结构)以及Unity 2023+版本的项目。
UGUI (Canvas-Based UI)
UGUI(基于画布的UI)
Canvas Setup
画布设置
| Render Mode | Use For | Notes |
|---|---|---|
| Screen Space - Overlay | HUD, menus | Always on top, no camera needed |
| Screen Space - Camera | Post-processing on UI | Assign render camera |
| World Space | In-game signs, health bars | Set event camera for interaction |
Performance rule: Separate static and dynamic UI into different Canvases. A Canvas rebuilds ALL children when any child changes.
| 渲染模式 | 适用场景 | 注意事项 |
|---|---|---|
| Screen Space - Overlay | HUD、菜单 | 始终置于顶层,无需相机 |
| Screen Space - Camera | 带后处理的UI | 需指定渲染相机 |
| World Space | 游戏内标识、血条 | 设置交互用的事件相机 |
性能规则: 将静态UI与动态UI拆分到不同画布中。当画布内任意子物体变化时,整个画布的所有子物体都会重建。
RectTransform Anchoring
RectTransform锚点设置
bash
Anchor presets control how elements resize with parent:
- Stretch-Stretch: Element fills parent (full-screen backgrounds)
- Center-Center: Fixed size at center (popup dialogs)
- Bottom-Left: Fixed corner position (minimap)
- Top-Stretch: Stretches horizontally, fixed at top (nav bar)Set anchors via the RectTransform anchor preset widget (hold Alt+Shift to also set pivot and position). Use , , , in code.
anchorMinanchorMaxoffsetMinoffsetMaxbash
锚点预设控制元素如何随父物体调整大小:
- Stretch-Stretch:元素填充父物体(全屏背景)
- Center-Center:固定尺寸居中(弹窗对话框)
- Bottom-Left:固定在左下角(小地图)
- Top-Stretch:水平拉伸,固定在顶部(导航栏)通过RectTransform锚点预设控件设置锚点(按住Alt+Shift可同时设置枢轴和位置)。在代码中可使用、、、属性。
anchorMinanchorMaxoffsetMinoffsetMaxLayout Components
布局组件
| Component | Purpose |
|---|---|
| Arrange children left-to-right |
| Arrange children top-to-bottom |
| Grid arrangement (inventory slots) |
| Override min/preferred/flexible size |
| Auto-resize to content |
| Maintain aspect ratio |
Disable to prevent unwanted stretching.
Layout.childForceExpandWidth/Height| 组件 | 用途 |
|---|---|
| 子物体从左到右排列 |
| 子物体从上到下排列 |
| 网格排列(背包格子) |
| 覆盖最小/首选/灵活尺寸 |
| 根据内容自动调整尺寸 |
| 保持宽高比 |
禁用可避免不必要的拉伸。
Layout.childForceExpandWidth/HeightEvent Handling
事件处理
csharp
using UnityEngine.UI;
using TMPro;
[SerializeField] Button startButton;
[SerializeField] TMP_InputField nameField;
[SerializeField] Slider volumeSlider;
void OnEnable()
{
startButton.onClick.AddListener(OnStartClicked);
nameField.onEndEdit.AddListener(OnNameChanged);
volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
}
void OnDisable()
{
startButton.onClick.RemoveListener(OnStartClicked);
nameField.onEndEdit.RemoveListener(OnNameChanged);
volumeSlider.onValueChanged.RemoveListener(OnVolumeChanged);
}Always in to prevent leaks and ghost references.
RemoveListenerOnDisablecsharp
using UnityEngine.UI;
using TMPro;
[SerializeField] Button startButton;
[SerializeField] TMP_InputField nameField;
[SerializeField] Slider volumeSlider;
void OnEnable()
{
startButton.onClick.AddListener(OnStartClicked);
nameField.onEndEdit.AddListener(OnNameChanged);
volumeSlider.onValueChanged.AddListener(OnVolumeChanged);
}
void OnDisable()
{
startButton.onClick.RemoveListener(OnStartClicked);
nameField.onEndEdit.RemoveListener(OnNameChanged);
volumeSlider.onValueChanged.RemoveListener(OnVolumeChanged);
}务必在中移除监听器,以避免内存泄漏和无效引用。
OnDisableTextMeshPro
TextMeshPro
Always use TextMeshPro (, ) over legacy . Import TMP Essentials when prompted. Use rich text tags: , , , for inline icons.
TMP_TextTextMeshProUGUIText<color=#FF0000><b><size=24><sprite=0>始终使用TextMeshPro(、)替代旧版。按提示导入TMP Essentials资源包。使用富文本标签:、、、用于插入内联图标。
TMP_TextTextMeshProUGUIText<color=#FF0000><b><size=24><sprite=0>UI Toolkit (USS/UXML)
UI Toolkit(USS/UXML)
Architecture
架构
text
UI Toolkit Stack:
UXML -- Structure (like HTML)
USS -- Styling (like CSS)
C# -- Logic (like JavaScript)text
UI Toolkit 栈:
UXML -- 结构(类似HTML)
USS -- 样式(类似CSS)
C# -- 逻辑(类似JavaScript)UXML Structure
UXML结构
xml
<ui:UXML xmlns:ui="UnityEngine.UIElements">
<ui:VisualElement class="container">
<ui:Label text="Player Stats" class="title" />
<ui:ProgressBar name="health-bar" title="HP" high-value="100" />
<ui:Button name="attack-btn" text="Attack" class="action-btn" />
<ui:ListView name="inventory-list" />
</ui:VisualElement>
</ui:UXML>xml
<ui:UXML xmlns:ui="UnityEngine.UIElements">
<ui:VisualElement class="container">
<ui:Label text="Player Stats" class="title" />
<ui:ProgressBar name="health-bar" title="HP" high-value="100" />
<ui:Button name="attack-btn" text="Attack" class="action-btn" />
<ui:ListView name="inventory-list" />
</ui:VisualElement>
</ui:UXML>USS Styling
USS样式设置
css
.container {
flex-direction: column;
padding: 10px;
background-color: rgba(0, 0, 0, 0.8);
border-radius: 8px;
}
.title {
font-size: 24px;
color: white;
-unity-font-style: bold;
margin-bottom: 10px;
}
.action-btn {
height: 40px;
background-color: #4CAF50;
color: white;
border-radius: 4px;
transition-duration: 0.2s;
}
.action-btn:hover {
background-color: #66BB6A;
scale: 1.05 1.05;
}Key USS differences from CSS: use prefix for Unity-specific properties. Flexbox is the layout model (default ). Use , for animations.
-unity-flex-direction: columntransition-durationtransition-propertycss
.container {
flex-direction: column;
padding: 10px;
background-color: rgba(0, 0, 0, 0.8);
border-radius: 8px;
}
.title {
font-size: 24px;
color: white;
-unity-font-style: bold;
margin-bottom: 10px;
}
.action-btn {
height: 40px;
background-color: #4CAF50;
color: white;
border-radius: 4px;
transition-duration: 0.2s;
}
.action-btn:hover {
background-color: #66BB6A;
scale: 1.05 1.05;
}USS与CSS的核心区别:Unity专属属性需添加前缀。布局模型采用Flexbox(默认)。使用、实现动画效果。
-unity-flex-direction: columntransition-durationtransition-propertyC# Integration
C#集成
csharp
[RequireComponent(typeof(UIDocument))]
public class StatsUI : MonoBehaviour
{
void OnEnable()
{
var root = GetComponent<UIDocument>().rootVisualElement;
var healthBar = root.Q<ProgressBar>("health-bar");
var attackBtn = root.Q<Button>("attack-btn");
var inventory = root.Q<ListView>("inventory-list");
attackBtn.RegisterCallback<ClickEvent>(OnAttack);
healthBar.value = player.Health;
// ListView binding
inventory.makeItem = () => new Label();
inventory.bindItem = (element, index) =>
((Label)element).text = items[index].Name;
inventory.itemsSource = items;
}
}Query elements with or . Register callbacks with . Always query from .
Q<T>("name")Q<T>(className: "class")RegisterCallback<EventType>rootVisualElementcsharp
[RequireComponent(typeof(UIDocument))]
public class StatsUI : MonoBehaviour
{
void OnEnable()
{
var root = GetComponent<UIDocument>().rootVisualElement;
var healthBar = root.Q<ProgressBar>("health-bar");
var attackBtn = root.Q<Button>("attack-btn");
var inventory = root.Q<ListView>("inventory-list");
attackBtn.RegisterCallback<ClickEvent>(OnAttack);
healthBar.value = player.Health;
// ListView绑定
inventory.makeItem = () => new Label();
inventory.bindItem = (element, index) =>
((Label)element).text = items[index].Name;
inventory.itemsSource = items;
}
}使用或查询元素。通过注册回调。务必从开始查询元素。
Q<T>("name")Q<T>(className: "class")RegisterCallback<EventType>rootVisualElementData Binding (Unity 2023.2+)
数据绑定(Unity 2023.2+)
csharp
// Runtime data binding with [CreateProperty] and INotifyBindablePropertyChanged
public class PlayerData : INotifyBindablePropertyChanged
{
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
private int _health;
[CreateProperty]
public int Health
{
get => _health;
set { _health = value; Notify(); }
}
void Notify([CallerMemberName] string prop = "")
=> propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(prop));
}Bind in UXML with or in C# with .
binding-path="Health"element.SetBinding("value", new DataBinding { dataSourcePath = ... })csharp
// 使用[CreateProperty]和INotifyBindablePropertyChanged实现运行时数据绑定
public class PlayerData : INotifyBindablePropertyChanged
{
public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;
private int _health;
[CreateProperty]
public int Health
{
get => _health;
set { _health = value; Notify(); }
}
void Notify([CallerMemberName] string prop = "")
=> propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(prop));
}在UXML中通过绑定,或在C#中通过绑定。
binding-path="Health"element.SetBinding("value", new DataBinding { dataSourcePath = ... })Common UI Patterns
常见UI模式
| Pattern | UGUI Approach | UI Toolkit Approach |
|---|---|---|
| Popup dialog | Enable/disable child panel | Add/remove from visual tree |
| Scroll list | ScrollRect + VerticalLayoutGroup | ListView (virtualized) |
| Drag-and-drop | IBeginDragHandler, IDragHandler, IEndDragHandler | PointerManipulator |
| Tab system | Toggle group + panels | RadioButtonGroup + display toggling |
| Tooltip | Follow cursor panel | Manipulator + VisualElement positioning |
| Screen fade | CanvasGroup.alpha tween | USS opacity transition |
| 模式 | UGUI实现方式 | UI Toolkit实现方式 |
|---|---|---|
| 弹窗对话框 | 启用/禁用子面板 | 在视觉树中添加/移除元素 |
| 滚动列表 | ScrollRect + VerticalLayoutGroup | ListView(虚拟化) |
| 拖拽功能 | IBeginDragHandler、IDragHandler、IEndDragHandler | PointerManipulator |
| 标签系统 | Toggle组 + 面板 | RadioButtonGroup + 显示切换 |
| 提示框 | 跟随光标面板 | Manipulator + VisualElement定位 |
| 屏幕淡入淡出 | CanvasGroup.alpha补间 | USS透明度过渡 |
Additional Resources
额外资源
Reference Files
参考文档
- -- Advanced UGUI patterns: scroll optimization, dynamic layouts, world-space interaction, localization, safe area handling, screen adaptation
references/ugui-patterns.md - -- Custom controls, ListView/TreeView mastery, custom manipulators, editor UI integration, theming, responsive layouts
references/ui-toolkit-advanced.md
- -- UGUI进阶模式:滚动优化、动态布局、世界空间交互、本地化、安全区域处理、屏幕适配
references/ugui-patterns.md - -- 自定义控件、ListView/TreeView精通、自定义操作器、编辑器UI集成、主题设置、响应式布局
references/ui-toolkit-advanced.md