UnityのUI ToolkitでVisualElementの並び順を動的に変更する方法についてまとめました。
Unity 2022.2.17
UI Toolkitにおける並び順
UI Toolkitでは、ツリーにおける各VisualElementの並び順が重要な意味を持ちます。
一つ目がレイアウトへの影響です。
UI ToolkitはFlexboxの概念に基づいたレイアウトシステムを採用しているため、子要素をその並び順に応じてレイアウトします。
また、並び順は描画順にも影響を与えます。
UI Toolkitでは、深さ優先探索により描画順が決定されます。
要するに、UI BuilderのHierarchyにおいてより上にあるものから優先的に描画されます。
本記事ではこのように重要な意味を持つ並び順をランタイムで制御する方法についてまとめます。
並び順を動的に変更するメソッド
並び順を動的に変更するメソッドとして、VisualElementには以下の拡張メソッドが定義されています。
VisualElement visualElement; visualElement.SendToBack(); // 最背面に移動 = Hierarchyにおける親の一番上の子要素に移動される visualElement.BringToFront(); // 最前面に移動 = Hierarchyにおける親の一番下の子要素の移動される visualElement.PlaceBehind(sibling); // siblingの背面に移動(parentが同じである必要がある) visualElement.PlaceInFront(sibling); // siblingの前面に移動(parentが同じである必要がある)
これらを使うことで各VisualElementの並び順を動的に変更することができます。
メソッドの挙動を確認する
最後に上述のメソッドを使って実際に並び順を変更してみます。
まずUI Builderで以下のようなレイアウトを組みます。
赤、緑、青のVisualElementを配置し、赤いVisualElementの子要素として、前面に移動するためのボタンと背面に移動するためのボタンを配置しました。
using UnityEditor; using UnityEngine; using UnityEngine.UIElements; public sealed class Example : EditorWindow { [SerializeField] private VisualTreeAsset visualTree; private void CreateGUI() { visualTree.CloneTree(rootVisualElement); var red = rootVisualElement.Q<VisualElement>("Red"); var moveForwardButton = rootVisualElement.Q<Button>("MoveForwardButton"); var moveBackwardButton = rootVisualElement.Q<Button>("MoveBackwardButton"); moveForwardButton.clickable.clicked += () => { // 前面に移動する var redIndex = red.parent.IndexOf(red); if (redIndex == red.parent.childCount - 1) { return; } var next = red.parent.ElementAt(redIndex + 1); red.PlaceInFront(next); }; moveBackwardButton.clickable.clicked += () => { // 背面に移動する var redIndex = red.parent.IndexOf(red); if (redIndex == 0) { return; } var previous = red.parent.ElementAt(redIndex - 1); red.PlaceBehind(previous); }; } [MenuItem("Window/Example")] public static void ShowWindow() { GetWindow<Example>(); } }
赤いVisualElementのボタンがクリックされた時に赤い要素の並び順を変更しています。
Window > Exampleからウィンドウを開いて挙動を確認します。
正常に動作していることを確認できました。