Version: 2021.1
言語: 日本語
UI Toolkit へのアクセス
レイアウトエンジン

ビジュアルツリー

UI Toolkit の最も基本的な構成要素は、ビジュアル要素です。ビジュアル要素は、親子関係を持つ階層ツリーに整列されます。下図は、階層ツリーの簡略化された例と、UI Toolkit での描画結果を示しています。

ビジュアルツリーの簡易化された階層構造
ビジュアルツリーの簡易化された階層構造

ビジュアル要素

VisualElement クラスは、ビジュアルツリーのすべてのノードの基本になります。VisualElement 基本クラスは、スタイル、レイアウトデータ、イベントハンドラーなど、すべてのコントロールに共通のプロパティを含んでいます。ビジュアル要素は、子や子孫のビジュアル要素を持つことができます。例えば、上の図では、最初の Box ビジュアル要素は、 LabelCheckboxSlider の 3 つの子ビジュアル要素を持っています。

スタイルシートを使って、ビジュアル要素の外観をカスタマイズできます。また、イベントコールバックを使ってビジュアル要素の動作を変更することもできます。

VisualElement は、コントロールなどの追加の動作や機能を定義するサブクラスに派生します。UI Toolkit には、特殊な動作をするさまざまなビルトインのコントロールが含まれています。例えば、以下のようなものがビルトインコントロールとして用意されています。

  • ボタン
  • トグル
  • テキスト入力フィールド

また、ビジュアル要素を組み合わせ、その動作を変更することで、カスタムのコントロールを作成することができます。ビルトインコントロールのリストは、コントロールのリファレンス ページを参照してください。

パネル

パネルは、ビジュアルツリーの親オブジェクトです。ビジュアルツリーは、ツリー内のビジュアル要素を描画するために、パネルに接続する必要があります。すべてのパネルは、エディターウィンドウなどのウィンドウに属します。パネルは、フォーカス制御やビジュアルツリーのイベントディスパッチも行います。

ビジュアルツリーの全ての要素は、ビジュアルツリーを保持するパネルへの直接の参照を保持しています。VisualElement のパネルとの接続を確認するには、この要素の panel プロパティをテストします。ビジュアル要素が接続されていない場合、テストは null を返します。

描画順

ビジュアルツリー内の要素の描画順序は、深さ優先検索に従います。子のビジュアル要素は親要素の上に重ねて表示されます。また、子要素は兄弟リストの順に描画されます。描画順序は以下の通りです。

  1. 一番上のビジュアル要素
  2. そのビジュアル要素の最初の子要素
  3. 子孫の要素の子要素

下の図は、上の例の描画順序を示しています。

ビジュアル要素の描画順序
ビジュアル要素の描画順序

ビジュアル要素の描画順序を変更するには、以下の機能を使用します。

兄弟姉妹のビジュアル要素に関しては、以下を使用します。

座標と位置システム

UI Toolkit では強力なレイアウトシステムを用い、個々の要素のスタイルプロパティのレイアウトのパラメーターに基づいて、個々の要素の位置やサイズを自動的に計算します。詳細は、レイアウトエンジンのページ を参照してください。

UI Toolkit には 2 種類の座標があります。

  • Relative: 要素の計算された位置に相対的な座標。レイアウトシステムは、要素の位置を計算し、オフセットとして座標を加えます。レイアウトエンジンが要素の位置を計算する際に子要素を考慮するため、子要素は親要素の位置に影響を与えます。
  • Absolute: 親要素に相対的な座標です。これにより、自動的なレイアウト計算は回避し、要素の位置を直接設定します。同じ親の下にある子要素は、要素の位置に影響を与えません。同様に、同じ親の下にある他の兄弟の位置やサイズにも影響を与えません。

各ビジュアル要素は、その位置を計算するために使用する座標系を決定します。どの座標系を使用するかは、要素のスタイルシートで設定できます。

以下のコードは、コードを使ってビジュアル要素の座標空間と位置を設定する方法を示しています。

    var newElement = new VisualElement();
        newElement.style.position = Position.Relative;
        newElement.style.left = 15;
        newElement.style.top = 35;

要素の原点は左上の角です。

レイアウトシステムは、各要素の VisualElement.layoutプロパティ (タイプ Rect) を計算します。これには要素の最終的な位置が含まれます。要素の相対位置または絶対位置が考慮されます。

layout.position は親の座標空間に相対的に、ポイントで表されます。

VisualElement には、要素の位置と回転に追加のローカルオフセットを加えるために使用するトランスフォームプロパティ (ITransform) があります。このオフセットは、計算されたレイアウトプロパティでは示されません。デフォルトでは、transform は同一です。

worldBound プロパティを使用して、レイアウト位置とトランスフォームの両方を考慮に入れて VisualElement の最終的なウィンドウ空間座標を取得します。この位置には、ウィンドウのヘッダーの高さが含まれます。

以下のコードサンプルでは、相対位置と絶対位置の違いを示しています。自動レイアウトシステムを使って、ウィンドウにボックスを加え、その位置を計算しています。あるボックスは、相対的なオフセットの 25 px、別のボックスは、絶対的な位置の 25 px, 25 px を示しています。

ビジュアル要素の配置
ビジュアル要素の配置

この例を実際に見るには、以下を行います。

  1. Assets > Scripts > Editor の順に選択し、PositioningTestWindow という C# スクリプトを作成します。
  2. 以下のコードを C# スクリプトにコピーします。
  3. エディターツールバーから、 Window > UI Toolkit > Positioning Test Window を選択します。

using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class PositioningTestWindow : EditorWindow
{
    [MenuItem("Window/UI Toolkit/Positioning Test Window")]
    public static void ShowExample()
    {
        var wnd = GetWindow<PositioningTestWindow>();
        wnd.titleContent = new GUIContent("Positioning Test Window");
    }

    public void CreateGUI()
    {
        for (int i = 0; i < 2; i++)
        {
            var temp = new VisualElement();
            temp.style.width = 70;
            temp.style.height = 70;
            temp.style.marginBottom = 2;
            temp.style.backgroundColor = Color.gray;
            rootVisualElement.Add(temp);
        }

        // 相対的ポジショニング
        var relative = new Label("Relative\nPos\n25, 0");
        relative.style.width = 70;
        relative.style.height = 70;
        relative.style.left = 25;
        relative.style.marginBottom = 2;
        relative.style.backgroundColor = new Color(0.2165094f, 0, 0.254717f);
        rootVisualElement.Add(relative);

        for (int i = 0; i < 2; i++)
        {
            var temp = new VisualElement();
            temp.style.width = 70;
            temp.style.height = 70;
            temp.style.marginBottom = 2;
            temp.style.backgroundColor = Color.gray;
            rootVisualElement.Add(temp);
        }

        // 絶対的ポジショニング
        var absolutePositionElement = new Label("Absolute\nPos\n25, 25");
        absolutePositionElement.style.position = Position.Absolute;
        absolutePositionElement.style.top = 25;
        absolutePositionElement.style.left = 25;
        absolutePositionElement.style.width = 70;
        absolutePositionElement.style.height = 70;
        absolutePositionElement.style.backgroundColor = Color.black;
        rootVisualElement.Add(absolutePositionElement);
    }
}

座標系間の変換

VisualElement.layout.positionVisualElement.layout.transform プロパティはローカル座標系と親座標系間の変換方法を定義します。

VisualElementExtensions 静的クラスでは、座標系間で点や矩形を変換する以下の拡張メソッドを提供します。

  • WorldToLocal は、Panel 空間の Vector2 または Rect を要素内の参照に変換します。
  • LocalToWorldVector2 または RectPanel 空間参照に変換します。
  • ChangeCoordinatesTo は要素のローカル空間の Vector2 または Rect を別の要素のローカル空間に変換します。
UI Toolkit へのアクセス
レイアウトエンジン