Создание времени выполнения представления списка UI
Версия: 2022.3+
В этом примере показано, как создать список представления runtime UI. В этом примере используются файлы UXML и USS непосредственно для создания структуры и стиля UI. Если вы новичок UI Toolkit и хотите использовать UI Builder для создания UI, обратитесь к Создать пример UI с UI Builder.
Примерный обзор
Этот пример создает простой экран выбора персонажа. Когда вы нажимаете на имя персонажа из списка слева, подробности о персонаже появляются справа.
Вы можете найти завершенные файлы, созданные этим примером, в хранилище GitHub.
Предварительные условия
Это руководство предназначено для разработчиков, знакомых со скриптами Unity Editor, UI Toolkit и C#. Перед началом работы ознакомьтесь со следующим:
Создать основной документ UI
Создайте основное представление Документ UI и файл USS для стилизации визуальных элементов. Добавьте два визуальных элемента в качестве контейнеров в Документ UI: один, который содержит список имен персонажей, и другой, который содержит подробности выбранного персонажа.
Создайте проект в Unity с любым шаблоном.
В окне Project создайте папку
UIдля хранения всех файлов документа и таблицы стилей UI.-
В папке
UIсоздайте Документ 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> В папке
UIсоздайте таблицу стилей USS с именем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;
}
/* "Normal" background color of the item */
.unity-collection-view__item
{
background-color: slategrey;
}
/* Background color of the item when it is being hovered */
.unity-collection-view__item:hover
{
background-color: gray;
}
/* Background color of the item when it is selected */
.unity-collection-view__item--selected
{
background-color: black;
}
Создать запись в списке UI Документ
Создайте документ UI и таблицу стилей для отдельных элементов в списке. Запись в списке символов состоит из цветной рамки фона и имени персонажа.
-
В папке
UIсоздайте Документ 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> В папке
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);
}
Создание образца данных для отображения
Создайте тестовые данные для заполнения списка персонажей в интерфейсе. Для этого списка опишите класс, хранящий имя персонажа, его класс и портрет.
В папке Asset создайте папку с именем
Scriptsдля хранения скриптов C#.-
В папке
Scriptsсоздайте скрипт C# с именемCharacterData.csсо следующим содержанием:using UnityEngine; public enum ECharacterClass { Knight, Ranger, Wizard } [CreateAssetMenu] public class CharacterData : ScriptableObject { public string CharacterName; public ECharacterClass Class; public Sprite PortraitImage; }Это создает элемент Character Data в меню Ассеты > Создать.
В папке Assets создайте папку с именем
Resources.В папке
Resourcesсоздайте папку с именемCharactersдля хранения всех данных образца символа.В папке
Charactersщелкните правой кнопкой мыши и выберите Создать > Character Data для создания экземпляраScriptableObject.Создайте больше экземпляров
CharacterDataи заполните их данными для замены.
Настройка сцены
Создайте UIDocument GameObject в SampleScene и добавьте UI Документ в качестве исходного ассета.
- В SampleScene, выберите GameObject > UI Toolkit > UI Документ.
- Выберите UIDocument GameObject в окне Hierarchy.
- Перетащите MainView.uxml из окна Project в поле Source Asset компонента UI Document в окне Inspector. Это ссылается на исходный ресурс в файле UXML.
Создание контроллеров для элемента списка и основного представления
Создайте два скрипта C# со следующими классами:
- A
CharacterListEntryControllerкласс, чтобы вывести данные экземпляра персонажа в интерфейсе записи списка. Ему нужно обратиться к метке имени персонажа и задать в ней имя переданного экземпляра. - A
CharacterListControllerкласс для списка персонажей в основном представлении иMonoBehaviourскрипт, который создает экземпляр и присваивает его визуальному дереву.
Примечание: CharacterListEntryController класс не является MonoBehaviour. Поскольку визуальные элементы UI Toolkit не являются GameObject, прикрепить к ним компоненты нельзя. Вместо этого класс прикрепляется к userData свойства в CharacterListController class.
-
В папке
Scriptsсоздайте скрипт C# с именем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; } } -
В папке
Scriptsсоздайте скрипт C# с именем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, так что вы не можете напрямую прикрепить его к GameObject. Чтобы преодолеть это, создайте скрипт MonoBehaviour и прикрепите его к тому же GameObject, что и UIDocument. В этом скрипте вам не нужно инстанционировать MainView.uxml, так как он уже инстанционирован компонентом UIDocument. Вместо этого, доступ к компоненту UIDocument для получения ссылки на уже инстанционированное визуальное дерево. Затем создайте экземпляр CharacterListController и передайте корневой элемент визуального дерева и шаблон UXML, используемый для отдельных элементов списка.
Примечание: При перезагрузке UI все связанные компоненты MonoBehaviour на том же GameObject, которые содержат компонент UIDocument, отключаются до перезагрузки и затем вновь включаются после перезагрузки. Поэтому вы должны поместить свой код, связанный с UI, в методы OnEnable и OnDisable этого MonoBehaviour. Дополнительную информацию см. в Жизненный цикл компонентов документа UI.
-
В папке
Scriptsсоздайте скрипт C# с именем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); } } В SampleScene, выберите UIDocument.
Перетащите
MainView.csв Добавить компонент в окне Inspector.Перетащите ListEntry.uxml в поле ListEntry Шаблон.
Перейдите в игровой режим, чтобы увидеть ваш UI в игровом окне.