Version: 2023.1
言語: 日本語
USS common properties
相対配置と絶対配置

レイアウトエンジンによる要素の配置

UI Toolkit には、レイアウトやスタイリングのプロパティに基づいて要素を配置するレイアウトエンジンが搭載されています。レイアウトエンジンは、HTML/CSS のレイアウトシステムである Flexbox のサブセットを実装した Yoga のレイアウト法則を使用しています。

デフォルトでは、すべての要素はレイアウトの一部です。レイアウトには以下のデフォルトの動作があります。

  • コンテナは子を垂直に配置します。
  • コンテナ矩形の位置は子の矩形を含みます。この動作は他のレイアウトプロパティによって制限される場合があります。
  • テキストを持つ VisualElement は、サイズ計算でテキストサイズを使用します。この動作は他のレイアウトプロパティによって制限される場合があります。

UI Toolkit には、ボタン、トグル、テキストフィールド、などの標準 UI コントロール用のビルトイン コントロール が含まれます。これらのビルトインコントロールには、レイアウトに影響するスタイルがあります。

主なスタイルプロパティ

以下は主なスタイルプロパティです。

  • Flex > Direction (flex-direction in USS): レイアウト方向の 主軸 を指定します。デフォルトは column で、 主軸 を上から下へ実行します。
  • Flex > Grow (flex-grow in USS): 要素が 主軸 方向にどのように展開するかを定義します。これは、同じ親の他の兄弟と共有される比率です。このプロパティは、要素を親のサイズ (兄弟を除く) 全体を占めるように伸ばす場合に便利です。これを行うには、 Flex > Grow の値を 1 に設定します。flex-grow1 に設定された 2 つの兄弟がある場合、それぞれ 主軸 に沿って親の利用可能なサイズの 50% に成長します。
  • Align > Align Items ( USS では align-items): 交差軸、つまり 主軸 に対して垂直な軸での要素の整列を定義します。例えば、flex-direction: columnalign-items: flex-end が設定された VisualElement に 2 つの Button (ボタン) がある場合、2 つの Button はコンテナの右端に押しつぶされます。align-items のオプションに flex-startflex-end という名前がついているのは、flex-direction の値に依存しているからです。
  • Align > Justify Content (justify-content in USS): 主軸 の要素の整列を定義します。例えば、flex-direction: columnjustify-content: flex-end が設定された VisualElement に 2 つの Button (ボタン) がある場合、2 つの Button はコンテナの下方の端に押しつぶされます。justify-content のオプションに flex-startflex-end という名前がついているのは、flex-direction の値に依存しているからです。

詳しくは、フレックスレイアウト を参照してください。

選択した要素に子要素がある場合、UI Builder ではヘッダーのトグルを使って ビューポート のフレックス (flex-) 関連のスタイルプロパティを切り替えることができます。下の画像は #menu 要素で利用可能なオプションです。

FlexPropertiesInCanvas
FlexPropertiesInCanvas

スタイルプロパティを使用すると、複雑で動的なレイアウトを作成できます。以下は、画面の右下端に Button を固定するレイアウトの例です。

BottomRightCornerButtonLayout
BottomRightCornerButtonLayout

このレイアウトの UXML は、各コンテナ VisualElement に設定されたインラインスタイルを示しており、以下のようになります。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
    <ui:VisualElement name="screen-is-blue" style="flex-grow: 1; justify-content: flex-end; background-color: blue;">
        <ui:VisualElement name="toolbar-is-orange" style="align-items: flex-end; background-color: orange;">
            <ui:Button text="Button" display-tooltip-when-elided="true" />
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>

コンテナは、その形状がわかるように色付けされています。ネストされた VisualElement コンテナを使用すると、各要素の位置とサイズを明示的に設定することなく、任意の動的なレイアウトを実現することができます。これにより、レイアウトが動的に保たれ、画面のサイズ変更など、より大きなコンテナのサイズ変更に自動的に調整されます。

絶対位置

UI Builder は Position スタイルプロパティもサポートしています。Position > Absolute (絶対) モードでは、デフォルトの Flexbox ベースのレイアウトエンジンから要素が見えなくなります。これは、まるでスペースを取らないのと同じです。Absolute 位置の要素は、Relative (相対) 位置の兄弟要素の上に表示されます。

Absolute 位置を使用する場合、Position > LeftTopRightBottom のスタイルプロパティを使用して、要素を親の各辺からオフセットしてサイズ調整します。これは、画面上の絶対座標を設定するのではなく、親要素からの相対的なオフセットを設定します。Relative モードを使用して親要素を配置することはできます。Left (左) オフセットと Right (右) オフセットの両方を設定すると、要素の Width (幅) スタイルプロパティは無視され、幅は以下の式でもとめられます。

element-computed-width = parent-width - left-offset - right-offset

LeftTopRightBottom はアンカーとして解釈することもできます。例えば、画面の左下に Button を固定することができます。

アンカーの例
アンカーの例

下の UXML はインラインスタイルを表示しています。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <ui:VisualElement style="flex-grow: 1;">
        <ui:VisualElement style="position: absolute; left: 0; bottom: 0;" />
    </ui:VisualElement>
</ui:UXML>

位置を決める際に、Left0 に設定するのと未設定にするのとでは、違いがあります。

  • Left を 0 に設定 オフセット 0 を設定することを意味します。
  • Left を設定しない とオフセットを設定せず、他のスタイルプロパティで要素の幅や高さを定義します。

これらのオフセットスタイルプロパティは、要素の青い選択境界線の各エッジとコーナーにある追加のサイズ変更ハンドルを介して、 Canvas で直接変更することも可能です。設定されているものと設定されていないものを区別することが重要です。そのため、Canvas には、要素の各辺にオレンジ色の四角形で “アンカー” トグルが表示されています。Canvas のハンドルは、どの “アンカー” が設定されているかによって、要素のサイズを視覚的に変更するときにどのスタイルプロパティを設定するかを調整します。例えば、Canvas の要素をその右枠のハンドルでサイズ変更しているとします。

  • LeftRight の両方のプロパティを設定する場合、ハンドルは Right プロパティを更新します。
  • Left を設定し Right を設定しない場合、ハンドルは Width プロパティを更新します。

相対と絶対の両方を使う

UI Toolkit のビルトインレイアウトエンジンを回避するので、通常、Absolute 位置モードの使用は推奨されません。また、全体的なレイアウトを変更すると、個々の要素を手動で更新する必要があり、メンテナンスに手間のかかる UI になる可能性があります。しかし、Absolute 位置モードの正当な使用例の 1 つはオーバーレイです。ポップアップやドロップダウンなど、複雑な UI を他の複雑な UI の上にオーバーレイするのに便利です。オーバーレイコンテナ自体にのみ Absolute 位置を使用し、オーバーレイ内部では Relative モードを使用することができます。以下は、単純な中央寄せポップアップの例です。

AbsolutePositionOverlayWithPopup そして、参考までに UXML を以下に示します。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
    <ui:VisualElement name="complex-ui-screen">
        <ui:Toggle label="Toggle" />
        <ui:MinMaxSlider picking-mode="Ignore" label="Min/Max Slider" min-value="10" max-value="12" low-limit="-10" high-limit="40" />
        <ui:Label text="Label" />
        <ui:Button text="Button" />
        <ui:Button text="Button" />
    </ui:VisualElement>
    <ui:VisualElement name="overlay" style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.71); align-items: center; justify-content: center;">
        <ui:VisualElement name="popup" style="background-color: rgba(70, 70, 70, 255);">
            <ui:Label text="Exit?" name="message" />
            <ui:Button text="Ok" name="ok-button" style="width: 108.3333px;" />
        </ui:VisualElement>
    </ui:VisualElement>
</ui:UXML>

上の例では、Absolute 位置の使い方を強調しています。すべての Position > LeftTopRightBottom0 に設定します。つまり、画面の端から 0 ピクセル離れた位置になります。これにより、#overlay 要素は、#complex-ui-screen コンテナ要素に重なるようになります。また、#overlay 要素に半透明の背景を設定すると、他の UI が暗く表示されるようになります。#overlay を使用して、Relative 位置を設定し、#popup コンテナ VisualElement を中央に配置します。

ベストプラクティス

以下のリストは、レイアウトエンジンのパフォーマンスを向上させるためのコツです。

  • 要素のサイズを定義するには、widthheight を設定します。

  • 要素に調整できるサイズを割り当てるには、flexGrow プロパティ (USS: flex-grow: <value>;) を使用します。flexGrow プロパティの値は、その兄弟によって決定されるときに、基本ウェイトを要素のサイズに割り当てます。

  • 水平レイアウトに切り替えるには、flexDirection プロパティを row (USS: flex-direction: row;) に設定します。

  • 元のレイアウト位置に基づいて要素をオフセットするには、相対位置を使用します。

  • 要素を親位置の矩形に対して相対的に配置するには、position プロパティを absolute に設定します。この場合、兄弟や親のレイアウトには影響しません。

その他の参考資料

USS common properties
相対配置と絶対配置