UnityのUIToolkitのランタイムUIを、UIBuilderを使って組み立てる方法について簡単にまとめました。
Unity 2022.1.1f1
はじめに
Unity2021.2から、UI Toolkit(旧UI Elements)でランタイムのUIを作成できるようになりました。
また、UI ToolkitにおけるUIレイアウト用ツールであるUI BuilderもUnityに組み込まれました。
本記事ではUI Builderを使って以下のようなランタイムのUIを組み立てる方法を簡潔にまとめます。
なおUI Toolkit(UI Elements)の基礎知識については前提知識とします。
UXMLなどの概念がわからない方は以下の記事にまとめていますので、必要に応じて参照してください。
ビューを作る
それではまずビューを作っていきます。
最初に、Create > UI Toolkit > Panel Settings Asset から Panel Settings を作成します。
このアセット自体は後ほど使用しますが、これと一緒に自動生成される UnityDefaultRuntimeTheme.tss が必要なので先に生成しておきます。
(マニュアルには UnityDefaultRuntimeTheme が最初から存在する前提で書かれているので、いずれ変更入るかも?
次に Window > UI Toolkit > UI Builder から UI Builder を開きます。
ウィンドウが開いたら以下の操作を行い、新しいUXMLを作成します。
- File > New から新しいファイルを作成
- Theme を Unity Default Runtime Theme に変更
- Hierarchy から uxml を選択
- Inspector > Canvas Size > Match Game View にチェックを入れる
次に ListView を Hierarchy にドラッグ & ドロップします。
ListView が作成されたら右クリックして FooList という名前にリネームしておきます。
また、Inspector からサイズ、背景色、枠線を適当に編集しておきます。
ここまでできたら Ctrl + S を押下して MainView という名前で任意の場所に保存しておきます。
次に同様にしてリストの要素となるボタンを配置した UXML を作成します。
これは ListElement という名前で任意の場所に保存しておきます。
ビューを制御するスクリプトを書く
次にビューを制御するためのスクリプトを書きます。
まず、ListElement 内の FooButton を制御するためのスクリプトを記述します。
using UnityEngine; using UnityEngine.UIElements; public sealed class FooButtonController { private readonly Button _button; public FooButtonController(VisualElement visualElement) { // VisualElementからButtonを取得する _button = visualElement.Q<Button>("FooButton"); _button.clicked += OnClick; } /// <summary> /// ボタンの文字列を設定する。 /// </summary> /// <param name="text"></param> public void SetText(string text) { _button.text = text; } private void OnClick() { // クリックされたログを出力する Debug.Log($"Clicked: {_button.text}"); } }
詳細はコメントに記述したとおりです。
次に、MainView 内の FooList を制御するためのスクリプトを書きます。
using System.Collections.Generic; using UnityEngine.UIElements; public sealed class FooListController { private IReadOnlyList<string> _buttonTexts; private readonly VisualTreeAsset _elementTemplate; private readonly ListView _fooList; public FooListController(VisualElement root, VisualTreeAsset elementTemplate, List<string> buttonTexts) { _fooList = root.Q<ListView>("FooList"); _elementTemplate = elementTemplate; _fooList.makeItem = () => { // リスト要素をインスタンス化して返す var element = _elementTemplate.Instantiate(); var buttonController = new FooButtonController(element); element.userData = buttonController; // ControllerはuserDataという汎用データ受け渡し用フィールドに格納しておく return element; }; _fooList.bindItem = (item, index) => { // リスト要素にデータを設定する var controller = (FooButtonController)item.userData; controller.SetText(buttonTexts[index]); }; _fooList.fixedItemHeight = 120; _fooList.itemsSource = buttonTexts; } }
最後にこれらのエントリポイントとなるスクリプトを作成します。
using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; public sealed class MainView : MonoBehaviour { [SerializeField] private VisualTreeAsset _elementTemplate; private void OnEnable() { // UIDocumentコンポーネントについては次節で説明 var uiDocument = GetComponent<UIDocument>(); var buttonTexts = new List<string> { "First", "Second", "Third" }; new FooListController(uiDocument.rootVisualElement, _elementTemplate, buttonTexts); } }
再生する
最後にシーンをセットアップして再生します。
UI Toolkit で作った UI をランタイムで表示するには、まず GameObject に UI Document コンポーネントをアタッチします。
このコンポーネントの Panel Settings に冒頭で作成した PanelSettings アセットをアサインします。
また、Source Asset に表示する UXML(今回はMainView)をアサインします。
次に、生成された UI を制御するために同じ GameObject に MainView コンポーネントをアタッチします。
Element Template に ListElement アセットをアサインしておきます。
あとは Unity を再生すれば、UI が表示されることが確認できます。