Version: 6000.3
语言: 中文
创建复杂的列表视图
将内容包装在滚动视图中

创建列表视图运行时 UI

版本: 2022.3+

此示例演示如何创建列表视图运行时 UI。此示例直接使用 UXML 和 USS 文件来创建 UI 的结构和样式。如果您是 UI Toolkit 的新手,并且想要使用 UI Builder 创建 UI,请参阅使用 UI Builder 创建示例 UI

示例概述

此示例创建了一个简单的字符选择屏幕。单击左侧列表中的角色名称时,该角色的详细信息将显示在右侧。

运行时 UI 的最终视图
运行时 UI 的最终视图

您可以在此 GitHub 存储库中找到此示例创建的已完成文件。

先决条件

本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发人员。在开始之前,请熟悉以下内容:

创建主UI文档

创建主视图 UI 文档和 USS 文件以设置视觉元素实例化或派生自 C# 的可视化树的节点VisualElement类。您可以设置外观样式、定义行为并将其作为 UI 的一部分显示在屏幕上。更多信息
请参阅术语表
.在UI文档中添加两个视觉元素作为容器:一个包含角色名称列表,另一个包含所选角色的详细信息。

主视图的 UI 布局设置
主视图的 UI 布局设置
  1. 使用任何模板在 Unity 中创建项目。

  2. 项目窗口一个窗口,显示您的内容Assets文件夹(项目选项卡)更多信息
    术语表中查看
    ,创建一个名为UI以存储所有 UI 文档和样式表文件。

  3. UI文件夹中,创建一个名为MainView.uxml内容如下:

    <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>
    
  4. UI文件夹中,创建一个名为MainView.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 文档和样式表。字符列表条目由彩色背景框和字符名称组成。

显示字符名称的列表条目
显示角色名称的列表条目
  1. UI文件夹中,创建一个名为ListEntry.uxml内容如下:

    <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>
    
  2. 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 中的字符列表。对于角色列表,创建一个包含角色名称、类和肖像图像的类。

  1. 在 Asset 文件夹中,创建一个名为Scripts以存储 C#脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性以及以您喜欢的任何方式响应用户输入。更多信息
    请参阅术语表
    .

  2. Scripts文件夹中,创建一个名为CharacterData.cs内容如下:

    using UnityEngine;
        
    public enum ECharacterClass
    {
        Knight, Ranger, Wizard
    }
        
    [CreateAssetMenu]
    public class CharacterData : ScriptableObject
    {
        public string CharacterName;
        public ECharacterClass Class;
        public Sprite PortraitImage;
    }
    

    这会在 资产(Assets) > 创建Create) 菜单中创建一个角色数据项。

  3. 在 Assets 文件夹中,创建一个名为Resources.

  4. Resources文件夹中,创建一个名为Characters以存储所有示例字符数据。

  5. Characters文件夹中,单击鼠标右键并选择 创建>角色数据(Create Character Data) 以创建ScriptableObject.

  6. 创造更多CharacterData实例并用占位符数据填充它们。

设置场景

创建 UIDocument游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表
,并将UI文档添加为源资产。

  1. 在 SampleScene 中,选择 游戏对象 > UI 工具包 > UI 文档
  2. 在“层次结构”窗口中选择 UIDocument 游戏对象。
  3. MainView.uxml 从“项目”窗口拖到 UI 文档组件的 源资产(Source Asset) 字段中检查器一个 Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
    请参阅术语表
    窗。这将源资产引用到UXL文件。

为列表条目和主视图创建控制器

使用以下类创建两个 C# 脚本:

  • 一个CharacterListEntryController类,在列表条目的 UI 中显示字符实例的数据。它需要访问字符名称的标签并将其设置为显示给定字符实例的名称。
  • 一个CharacterListControllerclass 用于主视图中的字符列表,以及MonoBehaviour实例化并将其分配给可视化树轻量级节点组成的对象图,用于保存窗口或面板中的所有元素。它定义了使用 UI 工具包构建的每个 UI。
    请参阅术语表
    .

注意:该CharacterListEntryController类不是MonoBehaviour.由于 UI 工具包中的视觉元素不是游戏对象,因此无法将组件附加到它们。相反,您将类附加到userData属性中的CharacterListController类。

  1. Scripts文件夹中,创建一个名为CharacterListEntryController.cs包含以下内容:

    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;
        }
    }
    
  2. Scripts文件夹中,创建一个名为CharacterListController.cs内容如下:

    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 模板。

注意:当界面重新加载时,任何关联的MonoBehaviour包含 UIDocument 组件的同一游戏对象上的组件在重新加载之前被禁用,然后在重新加载后重新启用。因此,您必须将与 UI 相关的代码放在OnEnableOnDisable这个的方法MonoBehaviour.有关更多信息,请参阅UI文档组件的生命周期

  1. Scripts文件夹中,创建一个名为MainView.cs内容如下:

    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);
        }
    }
    
  2. 在 SampleScene 中,选择 UIDocument

  3. MainView.cs以在“检查器”窗口中添加组件。

  4. ListEntry.uxml 拖到 ListEntry 模板字段

  5. 进入游戏模式以查看游戏视图中显示的 UI。

其他资源

创建复杂的列表视图
将内容包装在滚动视图中