Version: 2023.1
言語: 日本語
複雑なリストビューの作成
スクロールビュー内でコンテンツを折り返す

リストビューのランタイム UI の作成

バージョン: 2021.3 以降

この例は、リストビューのランタイム UI の作成方法を示すものです。この例では、UXML ファイルと USS ファイルを直接使用して、UI の構造とスタイルを作成します。UI Toolkit を初めて使用し、UI Builder を使用して UI を作成したい場合は、UI Builder でのサンプル UI の作成 を参照してください。

例の概要

この例は、簡単なキャラクター選択画面を作成します。左側のリストからキャラクター名をクリックすると、右側にキャラクターの詳細が表示されます。

ランタイム UI の最終的な見た目
ランタイム UI の最終的な見た目

この例で作成される完成されたファイルは、こちらの GitHub リポジトリ にあります。

要件

このガイドは、Unity エディター、UI Toolkit、および C# スクリプトに精通している開発者を対象としています。始める前に、以下をよく理解してください。 * UXML * ListView * Label * PanelSettings * UIDocument

メイン UI ドキュメントの作成

メインビューの UI ドキュメントと、ビジュアル要素のスタイルを設定するための USS ファイルを作成します。UI ドキュメントにコンテナとして 2 つのビジュアル要素を追加します。1 つはキャラクター名のリスト、もう 1 つは選択されたキャラクターの詳細を含みます。

メインビューの UI レイアウト設定
メインビューの UI レイアウト設定
  1. Unity で任意のテンプレートでプロジェクトを作成します。

  2. Project ウィンドウで、全ての UI ドキュメントとスタイルシートファイルを格納するための UI という名前のフォルダーを作成します。

  3. 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>
    
  4. 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;
        }
    
        #CharacterClass {
            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;
        }
    

リストエントリー UI ドキュメントの作成

リスト内の個々のエントリーの UI ドキュメントとスタイルシートを作成します。キャラクターリストのエントリーは、色付きの背景フレームとキャラクターの名前から構成されます。

キャラクター名を表示するリストエントリー
キャラクター名を表示するリストエントリー
  1. 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>
    
  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 フォルダー内に、C# スクリプトを格納するための Scripts というフォルダーを作成します。

  2. Scripts フォルダー内に、以下の内容を持つ CharacterData.cs という名前の C# スクリプトを作成します。

    using UnityEngine;
    
    public enum ECharacterClass
    {
        Knight, Ranger, Wizard
    }
    
    [CreateAssetMenu] //This adds an entry to the **Create** menu
    public class CharacterData : ScriptableObject
    {
        public string CharacterName;
        public ECharacterClass Class;
        public Sprite PortraitImage;
    }
    

    これにより、Assets > Create メニューに Character Data アイテムが作成されます。

  3. Assets フォルダー内に、Resources というフォルダーを作成します。

  4. Resources フォルダー内に、全てのサンプルキャラクターデータを格納するための Characters というフォルダーを作成します。

  5. Characters フォルダー内で右クリックし、Create > Character Data を選択して ScriptableObject のインスタンスを作成します。

  6. CharacterData インスタンスをさらに作成し、それらをプレースホルダーデータで埋めます。

シーンの設定

サンプルシーン内に UIDocument ゲームオブジェクトを作成し、UI Document をソースアセットとして加えます。

  1. サンプルシーンで GameObject > UI Toolkit > UI Document の順にクリックします。
  2. Hierarchy ウィンドウで UIDocument ゲームオブジェクトを選択します。
  3. Project ウィンドウから、MainView.uxml を、Inspector ウィンドウの UI Document コンポーネントの Source Asset フィールドにドラッグします。これにより、この UXML ファイルのソースアセットが参照されます。

リストエントリーおよびメインビュー用のコントローラーの作成

以下のクラスを使用して 2 つの C# スクリプトを作成します。

  • キャラクターインスタンスのデータをリストエントリーの UI に表示するための CharacterListEntryController クラス。これは、キャラクター名のラベルにアクセスし、指定のキャラクターインスタンスの名前を表示するためにそれを設定する必要があります。
  • メインビューのキャラクターリスト用の CharacterListController クラスと、それをインスタンス化してビジュアルツリーに割り当てる MonoBehaviour スクリプト。

ノート: CharacterListEntry クラスは MonoBehaviour ではありません。UI Toolkit のビジュアル要素はゲームオブジェクトではないので、これにコンポーネントをアタッチすることはできません。代わりに、CharacterListController クラス内の userData プロパティにこのクラスをアタッチします。

  1. Scripts フォルダー内に、以下の内容を含む CharacterListEntryController.cs という名前の C# スクリプトを作成します。

    using UnityEngine.UIElements;
    
    public class CharacterListEntryController
    {
        Label NameLabel;
    
        //This function retrieves a reference to the
        //character name label inside the UI element.
    
        public void SetVisualElement(VisualElement visualElement)
        {
            NameLabel = visualElement.Q<Label>("character-name");
        }
    
        //This function receives the character whose name this list
        //element displays. Since the elements listed
        //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)
        {
            NameLabel.text = characterData.CharacterName;
        }
    }
    
  2. Scripts フォルダー内に、以下の内容を含む CharacterListController.cs という名前の C# スクリプトを作成します。

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UIElements;
    
    public class CharacterListController
    {
        // UXML template for list entries
        VisualTreeAsset ListEntryTemplate;
    
        // UI element references
        ListView CharacterList;
        Label CharClassLabel;
        Label CharNameLabel;
        VisualElement CharPortrait;
    
        public void InitializeCharacterList(VisualElement root, VisualTreeAsset listElementTemplate)
        {
            EnumerateAllCharacters();
    
            // Store a reference to the template for the list entries
            ListEntryTemplate = listElementTemplate;
    
            // Store a reference to the character list element
            CharacterList = root.Q<ListView>("character-list");
    
            // Store references to the selected character info elements
            CharClassLabel = root.Q<Label>("character-class");
            CharNameLabel = root.Q<Label>("character-name");
            CharPortrait = root.Q<VisualElement>("character-portrait");
    
            FillCharacterList();
    
            // Register to get a callback when an item is selected
            CharacterList.onSelectionChange += OnCharacterSelected;
        }
    
        List<CharacterData> AllCharacters;
    
        void EnumerateAllCharacters()
        {
            AllCharacters = new List<CharacterData>();
            AllCharacters.AddRange(Resources.LoadAll<CharacterData>("Characters"));
        }
    
        void FillCharacterList()
        {
            // Set up a make item function for a list entry
            CharacterList.makeItem = () =>
            {
                // Instantiate the UXML template for the entry
                var newListEntry = 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
            CharacterList.bindItem = (item, index) =>
            {
                (item.userData as CharacterListEntryController).SetCharacterData(AllCharacters[index]);
            };
    
            // Set a fixed item height
            CharacterList.fixedItemHeight = 45;
    
            // Set the actual item's source list/array
            CharacterList.itemsSource = AllCharacters;
        }
    
        void OnCharacterSelected(IEnumerable<object> selectedItems)
        {
            // Get the currently selected item directly from the ListView
            var selectedCharacter = CharacterList.selectedItem as CharacterData;
    
            // Handle none-selection (Escape to deselect everything)
            if (selectedCharacter == null)
            {
                // Clear
                CharClassLabel.text = "";
                CharNameLabel.text = "";
                CharPortrait.style.backgroundImage = null;
    
                return;
            }
    
            // Fill in character details
            CharClassLabel.text = selectedCharacter.Class.ToString();
            CharNameLabel.text = selectedCharacter.CharacterName;
            CharPortrait.style.backgroundImage = new StyleBackground(selectedCharacter.PortraitImage);
        }
    }
    

コントローラースクリプトをメインビューにアタッチする

CharacterListControllerMonoBehaviour ではないので、ビジュアルツリーにアタッチされる必要があります。同じゲームオブジェクトに UI ドキュメントとしてアタッチできる MonoBehaviour スクリプトを作成してください。これが CharacterListController をインスタンス化してビジュアルツリーにアタッチします。

  1. Scripts フォルダー内に、以下の内容を含む MainView.cs という C# スクリプトを作成します。

    using UnityEngine;
    using UnityEngine.UIElements;
    
    public class MainView : MonoBehaviour
    {
        [SerializeField]
        VisualTreeAsset 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, ListEntryTemplate);
        }
    }
    
  2. サンプルシーン内で UIDocument を選択します。

  3. MainView.cs を Inspector ウィンドウの Add Component にドラッグします。

  4. ListEntry.uxmlListEntry Template フィールドにドラッグします。

  5. 再生モードを開始すると、ゲームビューに UI が表示されます。

その他の参考資料

複雑なリストビューの作成
スクロールビュー内でコンテンツを折り返す