はじめに
今回はUI Toolkit
にて以下の画像のような要素が入れ子になっているようなTreeView
を作成してみる記事になります。
↓TreeView
の公式ドキュメントの説明
docs.unity3d.com
概要
TreeView
は木構造なデータを表示することができるVisualElement
です。
A TreeView is a vertically scrollable area that links to, and displays, a list of items organized in a tree.
A TreeView is a ScrollView with additional logic to display a tree of vertically-arranged VisualElements. Each VisualElement in the tree is bound to a corresponding element in a data-source list. The data-source list can contain elements of any type.
// DeepL翻訳
TreeViewは、ツリー状に構成されたアイテムのリストにリンクして表示する、縦方向にスクロール可能な領域です。
TreeViewは、垂直方向に配置されたVisualElementのツリーを表示するためのロジックが追加されたScrollViewです。ツリー内の各VisualElementは、データソースリスト内の対応する要素にバインドされています。データ・ソース・リストには、任意のタイプの要素を含めることができます。
やり方
UXMLを記述する(UI Builder利用)
まずはUXML
にTreeView
を記述します。EditorフォルダにSampleTreeView.uxml
というUXMLファイルを作成し、UI BuilderによりTreeView
を作成していきます。
Projectビューで右クリックをし、Create > UI Toolkit > UI Document
を選択してUXML
ファイルを生成してください。名前はSampleTreeView.uxml
にしました。
Projectビュー上でダブルクリックをすると、UI Builder
が立ち上がってくれます。そしたら左下のLibrary
のStandard
にあるContainers/Tree View
をHierarchy上にドラッグ&ドロップしてみてください。
正しく操作ができていればSampleTreeView.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 /> </ui:UXML>
C#スクリプトでの記述
SampleTreeView.cs
ファイルを作成し、以下のように記述します。
public class SampleTreeView : EditorWindow { private static readonly List<Entry> Entries = new() { new Directory("Directory 1") { entries = new List<Entry> { new File("File 1"), new File("File 2"), new Directory("Directory 2") { entries = new List<Entry> { new File("File3") } } } }, new File("File4") }; // SampleTreeView.uxmlをインスペクターより指定する [SerializeField] private VisualTreeAsset uxml; // TreeViewの各要素のデータを格納しておくリスト // Doc: https://docs.unity3d.com/ScriptReference/UIElements.TreeViewItemData_1.html private readonly List<TreeViewItemData<Entry>> _rootItems = new(); // EditorWindowを開く [MenuItem("Sample/TreeView")] private static void OpenWindow() { GetWindow<SampleTreeView>("Sample Tree View"); } // イベント関数 ScriptableObject.Reset // Doc: https://docs.unity3d.com/ja/2023.1/ScriptReference/ScriptableObject.Reset.html private void Reset() { // EntriesからList<TreeViewItemData<Entry>>に変換をする var id = 0; foreach (var entry in Entries) { _rootItems.Add(entry.CreateTreeViewItemData(ref id)); } } private void CreateGUI() { // rootVisualElementをrootにしてVisualElementの木を構築する uxml.CloneTree(rootVisualElement); // TreeViewを検索する var treeView = rootVisualElement.Q<TreeView>(); // TreeViewにデータを入力する treeView.SetRootItems(_rootItems); // TreeViewの各要素の初期化処理を設定する // NOTE: 自作を指定したい場合は 「[SerializeField] VisualTreeAsset」と「VisualTreeAsset.CloneTree」 などで対応する treeView.makeItem = () => new Label(); // 初期化されたノードをデータにバインドするための設定 treeView.bindItem = (item, index) => { item.Q<Label>().text = treeView.GetItemDataForIndex<Entry>(index).GetName(); }; } // 以下バインドするためのデータ構造 [Serializable] public abstract class Entry { public abstract string GetName(); public abstract TreeViewItemData<Entry> CreateTreeViewItemData(ref int id); } [Serializable] public class Directory : Entry { public string name; public List<Entry> entries; public Directory(string name) { this.name = name; } public override string GetName() => name; public override TreeViewItemData<Entry> CreateTreeViewItemData(ref int id) { var children = new List<TreeViewItemData<Entry>>(entries.Count); foreach (var entry in entries) { children.Add(entry.CreateTreeViewItemData(ref id)); } return new TreeViewItemData<Entry>(id++, this, children); } } [Serializable] public class File : Entry { public string name; public File(string name) { this.name = name; } public override string GetName() => name; public override TreeViewItemData<Entry> CreateTreeViewItemData(ref int id) { return new TreeViewItemData<Entry>(id++, this); } } }
TreeViewItemData<T>
を経由してデータをバインドするのは最初は慣れが必要そうな気がします。結構UI ToolkitのListView
と扱い方が似ていますね。
Unity - Scripting API: TreeViewItemData<T0>
最後に[SerializeField]
したフィールドをInspectorビューから設定します。ProjectビューからSampleTreeView.cs
を選択して、InspectorビューからSampleTreeView.uxml
を設定してあげます。
動作確認する
メニューバーのSample > TreeView
を選択すると、以下のような画面が立ち上がるはずです。