Version: 2023.1
言語: 日本語
UI 構築の例
複雑なリストビューの作成

リストビューとツリービューの作成

リストビューとツリービューは、UI デザインにおけるよく使用される機能です。UI Toolkit を使用すると、カスタムエディターウィンドウで、またはランタイム時にリストビューとツリービューを作成できます。この例では、カスタムエディターウィンドウ内にリストビューとツリービューを作成する方法を紹介します。リストとツリーの構造を UXML で設定し、C# スクリプトで動的に入力します。

例の概要

この例では以下を表示する 4 つのエディターウィンドウを作成します。

  • 1 つの列を持つ惑星のリスト
  • 2 つの列を持つ惑星のリスト
  • 惑星のツリービュー
  • 2 つの列を持つ惑星のツリービュー

この例で作成するすべてのファイルは、GitHub リポジトリ にあります。

要件

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

C# でデータを作成する

2 つの惑星のグループとツリービューのルートノードで構成される C# スクリプトでデータを作成します。

  1. Unity で任意のテンプレートでプロジェクトを作成します。

  2. Project ウィンドウに、Editorという名前のフォルダーを作成します。

  3. Editor フォルダーに、PlanetsWindow.cs という名前の C# スクリプトを作成します。

  4. PlanetsWindow.cs のコンテンツを以下のように置き換えてください。

    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor;
    using UnityEngine.UIElements;
    
    // Base class for all windows that display planet information.
    public class PlanetsWindow : EditorWindow
    {
        [SerializeField]
        protected VisualTreeAsset uxml;
    
        // Nested interface that can be either a single planet or a group of planets.
        protected interface IPlanetOrGroup
        {
            public string name
            {
                get;
            }
    
            public bool populated
            {
                get;
            }
        }
    
        // Nested class that represents a planet.
        protected class Planet : IPlanetOrGroup
        {
            public string name
            {
                get;
            }
    
            public bool populated
            {
                get;
            }
    
            public Planet(string name, bool populated = false)
            {
                this.name = name;
                this.populated = populated;
            }
        }
    
        // Nested class that represents a group of planets.
        protected class PlanetGroup : IPlanetOrGroup
        {
            public string name
            {
                get;
            }
    
            public bool populated
            {
                get
                {
                    var anyPlanetPopulated = false;
                    foreach (Planet planet in planets)
                    {
                        anyPlanetPopulated = anyPlanetPopulated || planet.populated;
                    }
                    return anyPlanetPopulated;
                }
            }
    
            public readonly IReadOnlyList<Planet> planets;
    
            public PlanetGroup(string name, IReadOnlyList<Planet> planets)
            {
                this.name = name;
                this.planets = planets;
            }
        }
    
        // Data about planets in our solar system.
        protected static readonly List<PlanetGroup> planetGroups = new List<PlanetGroup>
        {
            new PlanetGroup("Inner Planets", new List<Planet>
            {
                new Planet("Mercury"),
                new Planet("Venus"),
                new Planet("Earth", true),
                new Planet("Mars")
            }),
            new PlanetGroup("Outer Planets", new List<Planet>
            {
                new Planet("Jupiter"),
                new Planet("Saturn"),
                new Planet("Uranus"),
                new Planet("Neptune")
            })
        };
    
        // Expresses planet data as a list of the planets themselves. Needed for ListView and MultiColumnListView.
        protected static List<Planet> planets
        {
            get
            {
                var retVal = new List<Planet>(8);
                foreach (var group in planetGroups)
                {
                    retVal.AddRange(group.planets);
                }
                return retVal;
            }
        }
    
        // Expresses planet data as a list of TreeViewItemData objects. Needed for TreeView and MultiColumnTreeView.
        protected static IList<TreeViewItemData<IPlanetOrGroup>> treeRoots
        {
            get
            {
                int id = 0;
                var roots = new List<TreeViewItemData<IPlanetOrGroup>>(planetGroups.Count);
                foreach (var group in planetGroups)
                {
                    var planetsInGroup = new List<TreeViewItemData<IPlanetOrGroup>>(group.planets.Count);
                    foreach (var planet in group.planets)
                    {
                        planetsInGroup.Add(new TreeViewItemData<IPlanetOrGroup>(id++, planet));
                    }
    
                    roots.Add(new TreeViewItemData<IPlanetOrGroup>(id++, group, planetsInGroup));
                }
                return roots;
            }
        }
    }
    

リストビューの作成

リストビューを作成するには、まず UI Builder を使って ListView UI コントロールを作成します。次に、ListView でカスタムエディターウィンドウを作成し、C# スクリプトでリストのデータを取得する場所を定義します。最後に、UXML ファイルを C# スクリプトに参照します。

  1. Editor フォルダーを右クリックします。

  2. Create > UI Toolkit > Editor Window を選択します。

  3. C# ボックスに PlanetsListView と入力し、USS チェックボックスをオフにします。これで 2 つのファイル PlanetsListView.uxmlPlanetsListView.cs が作成されます。

  4. PlanetsListView.uxml をダブルクリックして、UI Builder で開きます。

  5. Hierarchy ウィンドウで Label コントロールを削除し、ListView コントロールを追加します。

  6. Hierarchy ウィンドウで ListView 選択します。

  7. Inspector ウィンドウで、Fixed Item Height を 20 に設定します。

  8. 変更を保存します。PlanetsListView.uxml は以下のようになるはずです。

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
        <ui:ListView fixed-item-height="20" />
    </ui:UXML>
    
  9. PlanetsListView.cs の内容を以下のように置き換えます。

    using UnityEditor;
    using UnityEngine.UIElements;
    
    public class PlanetsListView : PlanetsWindow
    {
        [MenuItem("Planets/Standard List")]
        static void Summon()
        {
            GetWindow<PlanetsListView>("Standard Planet List");
        }
    
        void CreateGUI()
        {
            uxml.CloneTree(rootVisualElement);
            var listView = rootVisualElement.Q<ListView>();
    
            // Set ListView.itemsSource to populate the data in the list.
            listView.itemsSource = planets;
    
            // Set ListView.makeItem to initialize each entry in the list.
            listView.makeItem = () => new Label();
    
            // Set ListView.bindItem to bind an initialized entry to a data item.
            listView.bindItem = (VisualElement element, int index) =>
                (element as Label).text = planets[index].name;
        }
    }
    
  10. Unity の Project ウィンドウで PlanetsListView.cs を選択し、InspectorUxml フィールドに PlanetsListView.uxml をドラッグします。

  11. メニューから Planets > Standard List を選択すると、惑星のリストが表示されます。

複数の列を持つリストビューの作成

複数の列を持つリストビューを作成するには、まず MultiColumnListView UI コントロールを作成し、UXML ファイルで列の数と列のタイトルを定義します。次に、MultiColumnListView でカスタムエディターウィンドウを作成し、C# スクリプトで各列のリストのデータを取得する場所を定義します。最後に、UXML ファイルを C# スクリプトに参照します。

  1. Editor フォルダーを右クリックします。

  2. **Create** > **UI Toolkit** > **UI Document** の順に選択して UXML ファイルを作成し、PlanetsMultiColumnListView.uxml` と名付けます。

  3. テキストエディターで PlanetsMultiColumnListView.uxml を開きます。

  4. PlanetsMultiColumnListView.uxml の内容を以下のように置き換えます。

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
        <ui:MultiColumnListView fixed-item-height="20">
            <!-- Columns and Column aren't Visual Elements or controls. They are considered attributes of MultiColumnListView. -->
            <ui:Columns>
                <ui:Column name="name" title="Name" width="80" />
                <ui:Column name="populated" title="Populated?" width="80" />
            </ui:Columns>
        </ui:MultiColumnListView>
    </ui:UXML>
    
  5. Editor フォルダーに、PlanetsMultiColumnListView.cs という名前の C# スクリプトを作成します。

  6. PlanetsMultiColumnListView.cs の内容を以下のように置き換えます。

    using UnityEditor;
    using UnityEngine.UIElements;
    
    public class PlanetsMultiColumnListView : PlanetsWindow
    {
        [MenuItem("Planets/Multicolumn List")]
        static void Summon()
        {
            GetWindow<PlanetsMultiColumnListView>("Multicolumn Planet List");
        }
    
        void CreateGUI()
        {
            uxml.CloneTree(rootVisualElement);
            var listView = rootVisualElement.Q<MultiColumnListView>();
    
            // Set MultiColumnListView.itemsSource to populate the data in the list.
            listView.itemsSource = planets;
    
            // For each column, set Column.makeCell to initialize each cell in the column.
            // You can index the columns array with names or numerical indices.
            listView.columns["name"].makeCell = () => new Label();
            listView.columns["populated"].makeCell = () => new Toggle();
    
            // For each column, set Column.bindCell to bind an initialized cell to a data item.
            listView.columns["name"].bindCell = (VisualElement element, int index) =>
                (element as Label).text = planets[index].name;
            listView.columns["populated"].bindCell = (VisualElement element, int index) =>
                (element as Toggle).value = planets[index].populated;
        }
    }
    
  7. Unity の Project ウィンドウで PlanetsMultiColumnListView.cs を選択します。

  8. InspectorUxml フィールドに PlanetsMultiColumnListView.uxml をドラッグします。

  9. メニューから Planets > Multicolumn List を選択すると、2 列のリストが表示されます。1 つの列には惑星のリストがあります。 もう 1 つの列には、惑星に人が住んでいるかどうかを示すトグルがあります。

ツリービューの作成

カスタムエディターでツリービューを作成するには、まず TreeView UI コントロールを UXML ファイルに作成します。次に、TreeView でカスタムエディターウィンドウを作成して、どこで C# スクリプトでMultiColumnListView でカスタムエディターウィンドウを作成し、C# スクリプトで、ツリーノードのデータを取得する場所を定義します。最後に、UXML ファイルを C# スクリプトに参照します。

  1. Editor フォルダーに UXML ファイルを作成し、PlanetsTreeView.uxml と名付けます。

  2. PlanetsTreeView.uxml の内容を以下のように置き換えます。

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
        <ui:TreeView fixed-item-height="20" />
    </ui:UXML>
    
  3. Editorフォルダーに PlanetsTreeView.cs という名前の C# ファイルを作成します。

  4. PlanetsTreeView.cs の内容を以下のように置き換えます。

    using UnityEditor;
    using UnityEngine.UIElements;
    
    public class PlanetsTreeView : PlanetsWindow
    {
        [MenuItem("Planets/Standard Tree")]
        static void Summon()
        {
            GetWindow<PlanetsTreeView>("Standard Planet Tree");
        }
    
        void CreateGUI()
        {
            uxml.CloneTree(rootVisualElement);
            var treeView = rootVisualElement.Q<TreeView>();
    
            // Call TreeView.SetRootItems() to populate the data in the tree.
            treeView.SetRootItems(treeRoots);
    
            // Set TreeView.makeItem to initialize each node in the tree.
            treeView.makeItem = () => new Label();
    
            // Set TreeView.bindItem to bind an initialized node to a data item.
            treeView.bindItem = (VisualElement element, int index) =>
                (element as Label).text = treeView.GetItemDataForIndex<IPlanetOrGroup>(index).name;
        }
    }
    
  5. Unity の Project ウィンドウで PlanetsTreeView.cs を選択します。

  6. InspectorUxml フィールドに PlanetsTreeView.uxml をドラッグします。

  7. メニューから Planets > Standard Tree を選択すると、ノードでグループ化された 2 つの惑星リストが表示されます。各ノードの横には小さな矢印があります。矢印を選択すると、ウィンドウにグループの惑星が表示されます。

複数の列を持つツリービューの作成

カスタムエディターで複数の列を持つツリービューを作成するには、まず TreeView UI コントロールを UXML ファイルに作成します。次に、MultiColumnTreeView でカスタムエディターウィンドウを作成して、どこで C# スクリプトでMultiColumnListView でカスタムエディターウィンドウを作成し、C# スクリプトでツリーノードのデータを取得する場所を定義します。最後に、UXML ファイルを C# スクリプトに参照します。

  1. Editor フォルダーに UXML ファイルを作成し、PlanetsMultiColumnTreeView.uxml と名付けます。

  2. PlanetsMultiColumnTreeView.uxml の内容を以下のように置き換えます。

    <ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
        <ui:MultiColumnTreeView fixed-item-height="20">
            <!-- Columns and Column aren't Visual Elements or controls; they are considered attributes of MultiColumnListView. -->
            <ui:Columns>
                <ui:Column name="name" title="Name" width="120" />
                <ui:Column name="populated" title="Populated?" width="80" />
            </ui:Columns>
        </ui:MultiColumnTreeView>
    </ui:UXML>
    
  3. Editor フォルダーに PlanetsMultiColumnTreeView.cs という C# ファイルを作成します。

  4. PlanetsMultiColumnTreeView.cs の内容を以下のように置き換えます。

    using UnityEditor;
    using UnityEngine.UIElements;
    
    public class PlanetsMultiColumnTreeView : PlanetsWindow
    {
        [MenuItem("Planets/Multicolumn Tree")]
        static void Summon()
        {
            GetWindow<PlanetsMultiColumnTreeView>("Multicolumn Planet Tree");
        }
    
        void CreateGUI()
        {
            uxml.CloneTree(rootVisualElement);
            var treeView = rootVisualElement.Q<MultiColumnTreeView>();
    
            // Call MultiColumnTreeView.SetRootItems() to populate the data in the tree.
            treeView.SetRootItems(treeRoots);
    
            // For each column, set Column.makeCell to initialize each node in the tree.
            // You can index the columns array with names or numerical indices.
            treeView.columns["name"].makeCell = () => new Label();
            treeView.columns["populated"].makeCell = () => new Toggle();
    
            // For each column, set Column.bindCell to bind an initialized node to a data item.
            treeView.columns["name"].bindCell = (VisualElement element, int index) =>
                (element as Label).text = treeView.GetItemDataForIndex<IPlanetOrGroup>(index).name;
            treeView.columns["populated"].bindCell = (VisualElement element, int index) =>
                (element as Toggle).value = treeView.GetItemDataForIndex<IPlanetOrGroup>(index).populated;
        }
    }
    
  5. Unity の Project ウィンドウで PlanetsMultiColumnTreeView.cs を選択します。

  6. InspectorUxml フィールドに PlanetsMultiColumnTreeView.uxml をドラッグします。

  7. Planets > Multicolumn Tree を選択すると、2 列のリストが表示されます。最初の列には、ノードでグループ化された惑星のリストが 2 つあります。各ノードの横には矢印があります。矢印を選択すると、ウィンドウにそのグループの惑星とトグルのリストが表示されます。

その他の参考資料

UI 構築の例
複雑なリストビューの作成