版本: 2022.3+
此示例演示如何运行时创建列表视图UI(用户界面) 允许用户与您的应用程序交互。Unity 目前支持三种 UI 系统。 更多信息
参见 术语表。此示例直接使用 UXML 和 USS 文件来创建 UI 的结构和样式。如果您不熟悉 UI 工具包并希望使用 UI Builder 创建 UI,请参阅 使用 UI Builder 创建示例 UI。
此示例创建了一个简单的角色选择屏幕。当您从左侧列表中点击角色名称时,角色的详细信息将显示在右侧。
您可以在此 GitHub 存储库 中找到此示例创建的完整文件。
本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发人员。在开始之前,请熟悉以下内容
创建主视图 UI 文档和一个 USS 文件来设置视觉元素视觉树的一个节点,它实例化或派生自 C# VisualElement
类。您可以设置外观样式、定义行为并在屏幕上将其显示为 UI 的一部分。 更多信息
参见 术语表的样式。在 UI 文档中添加两个视觉元素作为容器:一个包含角色名称列表,另一个包含所选角色的详细信息。
在 Unity 中使用任何模板创建一个项目。
在项目窗口显示 Assets
文件夹内容的窗口(项目选项卡) 更多信息
参见 术语表中,创建一个名为 UI
的文件夹来存储所有 UI 文档和样式表文件。
在 UI
文件夹中,创建一个名为 MainView.uxml
的 UI 文档,其内容如下
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<Style src="MainView.uss" />
<ui:VisualElement name="background">
<ui:VisualElement name="main-container">
<ui:ListView focusable="true" name="character-list" />
<ui:VisualElement name="right-container">
<ui:VisualElement name="details-container">
<ui:VisualElement name="details">
<ui:VisualElement name="character-portrait" />
</ui:VisualElement>
<ui:Label text="Label" name="character-name" />
<ui:Label text="Label" display-tooltip-when-elided="true" name="character-class" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
在 UI
文件夹中,创建一个名为 MainView.uss
的 USS 样式表,其内容如下
#background {
flex-grow: 1;
align-items: center;
justify-content: center;
background-color: rgb(115, 37, 38);
}
#main-container {
flex-direction: row;
height: 350px;
}
#character-list {
width: 230px;
border-color: rgb(49, 26, 17);
border-width: 4px;
background-color: rgb(110, 57, 37);
border-radius: 15px;
margin-right: 6px;
}
#character-name {
-unity-font-style: bold;
font-size: 18px;
}
#character-class {
margin-top: 2px;
margin-bottom: 8px;
padding-top: 0;
padding-bottom: 0;
}
#right-container {
justify-content: space-between;
align-items: flex-end;
}
#details-container {
align-items: center;
background-color: rgb(170, 89, 57);
border-width: 4px;
border-color: rgb(49, 26, 17);
border-radius: 15px;
width: 252px;
justify-content: center;
padding: 8px;
height: 163px;
}
#details {
border-color: rgb(49, 26, 17);
border-width: 2px;
height: 120px;
width: 120px;
border-radius: 13px;
padding: 4px;
background-color: rgb(255, 133, 84);
}
#character-portrait {
flex-grow: 1;
-unity-background-scale-mode: scale-to-fit;
}
.unity-collection-view__item {
justify-content: center;
}
为列表中的各个条目创建 UI 文档和样式表。角色列表条目包括一个彩色背景框架和角色的名称。
在 UI
文件夹中,创建一个名为 ListEntry.uxml
的 UI 文档,其内容如下
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<Style src="ListEntry.uss" />
<ui:VisualElement name="list-entry">
<ui:Label text="Label" display-tooltip-when-elided="true" name="character-name" />
</ui:VisualElement>
</ui:UXML>
在 UI
文件夹中,创建一个名为 ListEntry.uss
的样式表文件,其内容如下
#list-entry {
height: 41px;
align-items: flex-start;
justify-content: center;
padding-left: 10px;
background-color: rgb(170, 89, 57);
border-color: rgb(49, 26, 17);
border-width: 2px;
border-radius: 15px;
}
#character-name {
-unity-font-style: bold;
font-size: 18px;
color: rgb(49, 26, 17);
}
创建示例数据以填充 UI 中的角色列表。对于角色列表,创建一个类来保存角色名称、类别和肖像图像。
在 Asset 文件夹中,创建一个名为 Scripts
的文件夹来存储您的 C#脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间推移修改组件属性并以任何您喜欢的方式响应用户输入。 更多信息
参见 术语表。
在 Scripts
文件夹中,创建一个名为 CharacterData.cs
的 C# 脚本,其内容如下
using UnityEngine;
public enum ECharacterClass
{
Knight, Ranger, Wizard
}
[CreateAssetMenu]
public class CharacterData : ScriptableObject
{
public string CharacterName;
public ECharacterClass Class;
public Sprite PortraitImage;
}
这将在 Assets > Create 菜单中创建 角色数据项。
在 Assets 文件夹中,创建一个名为 Resources
的文件夹。
在 Resources
文件夹中,创建一个名为 Characters
的文件夹来存储所有示例角色数据。
在 Characters
文件夹中,右键单击并选择 Create > Character Data 以创建 ScriptableObject
的实例。
创建更多 CharacterData
实例并使用占位符数据填充它们。
在 SampleScene 中创建一个 UIDocument游戏对象Unity 场景中的基本对象,可以表示角色、道具、场景、摄像机、路径点等等。游戏对象的功能由附加到它的组件定义。 更多信息
参见 术语表,并将 UI 文档作为源资产添加。
创建两个具有以下类的 C# 脚本
CharacterListEntryController
类,用于在列表条目的 UI 中显示角色实例的数据。它需要访问角色名称的标签并将其设置为显示给定角色实例的名称。CharacterListController
类,用于主视图中的角色列表,以及一个 MonoBehaviour
脚本,它实例化并将其分配给视觉树一个对象图,由轻量级节点组成,它保存窗口或面板中的所有元素。它定义了您使用 UI 工具包构建的每个 UI。
注意:CharacterListEntryController
类不是 MonoBehaviour
。由于 UI 工具包中的视觉元素不是游戏对象,因此您无法将组件附加到它们。相反,您将类附加到 CharacterListController
类中的 userData
属性。
在 Scripts
文件夹中,创建一个名为 CharacterListEntryController.cs
的 C# 脚本,其内容如下
using UnityEngine.UIElements;
public class CharacterListEntryController
{
Label m_NameLabel;
// This function retrieves a reference to the
// character name label inside the UI element.
public void SetVisualElement(VisualElement visualElement)
{
m_NameLabel = visualElement.Q<Label>("character-name");
}
// This function receives the character whose name this list
// element is supposed to display. Since the elements list
// in a `ListView` are pooled and reused, it's necessary to
// have a `Set` function to change which character's data to display.
public void SetCharacterData(CharacterData characterData)
{
m_NameLabel.text = characterData.CharacterName;
}
}
在 Scripts
文件夹中,创建一个名为 CharacterListController.cs
的 C# 脚本,其内容如下
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class CharacterListController
{
// UXML template for list entries
VisualTreeAsset m_ListEntryTemplate;
// UI element references
ListView m_CharacterList;
Label m_CharClassLabel;
Label m_CharNameLabel;
VisualElement m_CharPortrait;
List<CharacterData> m_AllCharacters;
public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
{
EnumerateAllCharacters();
// Store a reference to the template for the list entries
m_ListEntryTemplate = listElementTemplate;
// Store a reference to the character list element
m_CharacterList = root.Q<ListView>("character-list");
// Store references to the selected character info elements
m_CharClassLabel = root.Q<Label>("character-class");
m_CharNameLabel = root.Q<Label>("character-name");
m_CharPortrait = root.Q<VisualElement>("character-portrait");
FillCharacterList();
// Register to get a callback when an item is selected
m_CharacterList.selectionChanged += OnCharacterSelected;
}
void EnumerateAllCharacters()
{
m_AllCharacters = new List<CharacterData>();
m_AllCharacters.AddRange(Resources.LoadAll<CharacterData>("Characters"));
}
void FillCharacterList()
{
// Set up a make item function for a list entry
m_CharacterList.makeItem = () =>
{
// Instantiate the UXML template for the entry
var newListEntry = m_ListEntryTemplate.Instantiate();
// Instantiate a controller for the data
var newListEntryLogic = new CharacterListEntryController();
// Assign the controller script to the visual element
newListEntry.userData = newListEntryLogic;
// Initialize the controller script
newListEntryLogic.SetVisualElement(newListEntry);
// Return the root of the instantiated visual tree
return newListEntry;
};
// Set up bind function for a specific list entry
m_CharacterList.bindItem = (item, index) =>
{
(item.userData as CharacterListEntryController)?.SetCharacterData(m_AllCharacters[index]);
};
// Set a fixed item height matching the height of the item provided in makeItem.
// For dynamic height, see the virtualizationMethod property.
m_CharacterList.fixedItemHeight = 45;
// Set the actual item's source list/array
m_CharacterList.itemsSource = m_AllCharacters;
}
void OnCharacterSelected(IEnumerable<object> selectedItems)
{
// Get the currently selected item directly from the ListView
var selectedCharacter = m_CharacterList.selectedItem as CharacterData;
// Handle none-selection (Escape to deselect everything)
if (selectedCharacter == null)
{
// Clear
m_CharClassLabel.text = "";
m_CharNameLabel.text = "";
m_CharPortrait.style.backgroundImage = null;
return;
}
// Fill in character details
m_CharClassLabel.text = selectedCharacter.Class.ToString();
m_CharNameLabel.text = selectedCharacter.CharacterName;
m_CharPortrait.style.backgroundImage = new StyleBackground(selectedCharacter.PortraitImage);
}
}
CharacterListController
不是 MonoBehaviour
,因此您无法将其直接附加到游戏对象。为了克服这个问题,创建一个 MonoBehaviour
脚本并将其附加到与 UIDocument 相同的游戏对象。在此脚本中,您不需要实例化 MainView.uxml
,因为它已由 UIDocument 组件实例化。相反,访问 UIDocument 组件以获取已实例化视觉树的引用。然后,创建 CharacterListController
的实例并传入视觉树的根元素以及用于单个列表元素的 UXML 模板。
注意:当 UI 重新加载时,包含 UIDocument 组件的相同游戏对象上的任何关联的 MonoBehaviour
组件在重新加载之前会被禁用,然后在重新加载后重新启用。因此,您必须将与 UI 相关的代码放在此 MonoBehaviour
的 OnEnable
和 OnDisable
方法中。有关更多信息,请参阅 在游戏视图中渲染 UI。
在 Scripts
文件夹中,创建一个名为 MainView.cs
的 C# 脚本,其内容如下
using UnityEngine;
using UnityEngine.UIElements;
public class MainView : MonoBehaviour
{
[SerializeField]
VisualTreeAsset m_ListEntryTemplate;
void OnEnable()
{
// The UXML is already instantiated by the UIDocument component
var uiDocument = GetComponent<UIDocument>();
// Initialize the character list controller
var characterListController = new CharacterListController();
characterListController.InitializeCharacterList(uiDocument.rootVisualElement, m_ListEntryTemplate);
}
}
在 SampleScene 中,选择 UIDocument。
将 MainView.cs
拖到检查器窗口中的 添加组件。
将 ListEntry.uxml 拖到 ListEntry Template 字段。
进入播放模式以查看在游戏视图中显示的 UI。