Version: 2022.2
言語: 日本語
カスタムコントロール
Expose custom control to UXML and UI Builder

カスタムコントロールの作成

カスタムコントロールを作成するには、カスタムコントロールの C# クラスを作成し、それを初期化する必要があります。これは UXML や UI Builder で使用できるように公開できます。また、データにバインドすることも可能です。

カスタムコントロールクラスの作成

VisualElement クラスから派生する、あるいは VisualElement クラスのサブクラスから派生する、C# クラスを作成します。例えば、BindableElement の代わりに BaseField ジェネリック基本クラスから派生する、バインド可能なカスタムコントロールを作成できます。これには以下のような利点があります。

  • 指定したジェネリック型パラメーターの INotifyValueChanged インターフェースを実装します。
  • デフォルトでコントロールがフォーカス可能になります。
  • 左側にラベル要素、右側に入力を配置した、水平レイアウトを提供します。
FloatField は、BaseField から継承される、UI Toolkit のビルトインコントロールです。<br/>A. ラベル要素<br/>B. 入力要素
FloatField は、BaseField から継承される、UI Toolkit のビルトインコントロールです。
A. ラベル要素
B. 入力要素

ノート: ビルトイン UI コントロールから派生するカスタムコントロールを作成することも、その内部階層と既存の USS クラスに関する理解があれば可能です。この方法で作成したカスタムコントロールは、将来変更される可能性のある内部構造に依存してしまう場合があるため、Unity では、これを行うことは推奨していません。

カスタムコントロールを初期化する

カスタムコントロールは VisualElement から継承されます。VisualElement はゲームオブジェクトの生存期間には縛られず、以下のどのコールバックも受け取りません。

  • Awake()
  • OnEnable()
  • OnDisable()
  • OnDestroy()

カスタムコントロールは、そのコンストラクター内で初期化できます。ただし、アプリケーションに必要であれば、カスタムコントロールが UI に追加されるまで初期化を遅らせることができます。これを行うには、AttachToPanelEvent のコールバックを登録します。カスタムコントロールが UI から削除されたことを検出するには DetachFromPanelEvent コールバックを使用します。

void OnEnable()
{
    var myCustomElement = rootVisualElement.Q(className: "my-custom-element");
    myCustomElement.RegisterCallback<AttachToPanelEvent>(e =>
        { /* do something here when element is added to UI */ });
    myCustomElement.RegisterCallback<DetachFromPanelEvent>(e =>
        { /* do something here when element is removed from UI */ });
}

UI Toolkit はこれら 2 つのイベントを全ての要素に対してディスパッチし、カスタムの VisualElement サブクラスを必要としません。詳細は パネルイベント を参照してください。

カスタムコントロールを UXML と UI Builder に公開する

カスタムコントロールを UXML と UI Builder で使用するには、それを公開する必要があります。カスタムコントロールを公開するには、UxmlFactory<T> から派生する Factory クラスを定義 します。

カスタムコントロールに新しい属性を追加して UXML で使用することができます。カスタムコントロールに新しい属性を追加するには、UxmlTraits から派生する Traits クラスを定義し、要素の属性の定義 で説明されている Init() メソッドをオーバーライドします。UI Builder は、Inspector で UXML プロパティの値が変更された時に、Viewport 用に作成されたビジュアル要素が更新されるようにするにあたって、このメソッドに依存します。

UI Builder の Inspector でカスタムコントロールの UXML プロパティを使用するには、UXML と C# スクリプトでプロパティ名を一致させる必要があります。UXML では標準のケバブケース表記を使用し、C# ではキャメルケースまたはパスカルケースを使用します。例えば、C# で MyFloat あるいは myFloat という名前のプロパティは、UXML では my-float となります。

カスタムコントロールをデータにバインドする

シリアル化されたプロパティにカスタムコントロールをバインドすることで、コントロールとプロパティの間で値を同期させます。

カスタムコントロールをデータに バインド するには、以下を行います。

詳細は SerializedObject のデータバインディング を参照してください。

バインド可能なカスタムコントロールの例は、バインド可能なカスタムコントロールの作成 で参照できます。

USS でのカスタムコントロールのスタイル設定

カスタムコントロールの見た目をカスタマイズするには、ビルトインコントロールの場合と同様に、USS を使用します。また、USS のカスタムプロパティ を作成してカスタムコントロールのスタイルを設定することもできます。

ノート: UI Builder の Inspector ウィンドウには、USS のカスタムプロパティは表示されません。USS のカスタムプロパティを編集するには、テキストエディターを使って USS ファイルを直接編集してください。

C# でカスタムコントロールのカスタム USS プロパティを操作するには、CustomStyleProperty 構造体と CustomStylesResolvedEvent イベントを使用します。

CustomStyleProperty は、スタイルシートから読み取ったプロパティの名前とタイプを記述します。

UI Toolkit は、カスタム USS プロパティを直接受け取る要素に対して CustomStylesResolvedEvent をディスパッチします。セレクターと一致する要素に対して、(セレクターの規則にカスタムプロパティの値が含まれる場合に) イベントがディスパッチされます。UI Toolkit は、値を継承する要素にはイベントをディスパッチしません。このイベントは ICustomStyle オブジェクトへの参照を持ちます。その TryGetValue() メソッドを使用して CustomStyleProperty の有効値を読み取る必要があります。このメソッドには、各種の CustomStyleProperty のオーバーロードがあります。

カスタムコントロールの例を用いたカスタムスタイルについては、カスタムコントロールのカスタムスタイルを作成する を参照してください。

ノート: カスタムスタイルプロパティに遷移を定義することはできません。

カスタムコントロールのイベントの処理

カスタムコントロールのイベント処理方法に関する詳細は、イベントの処理 を参照してください。

ノート:

  • Unity は、現在フォーカスされている要素にキーボードイベントをディスパッチします。カスタムコントロールの キーボードイベント を処理するには、focus に関連するプロパティを設定します。
  • タッチやマウスの入力イベントを処理するには、適したイベントタイプ (ポインターイベントマウスイベント など) のコールバックをコンストラクター内で登録します。

UI Builder でのカスタムコントロールの使用

UI Builder でビジュアルツリーにカスタムコントロールを追加するには、以下を行います。

  1. Library > Project > Custom Controls (C#) を選択します。
  2. カスタムコントロールを Hierarchy ウィンドウにドラッグします。

ベストプラクティスとヒント

ベストプラクティス:

  • 任意のカスタムコントロールに対応するプロパティと、その動作のその他の機能的側面を、 UXML プロパティとして公開し、カスタムコントロールの見た目に影響を与えるプロパティを USS プロパティとして公開します。
  • 他の要素との名前の競合を避けるために、短くて読みやすい固有の名前空間を使用します。
  • UXML の属性はプリミティブにします。UXML で指定できるデータは、プリミティブ型データの集合に限られます。UXML は複雑なデータ構造やコレクションをサポートしていません。複雑なデータは、UXML ではなく C# スクリプトまたはデータバインディングによって、ランタイムにカスタムコントロールに渡します。
  • C# では、USS のクラスや名前を定数として公開します。これにより、UQuery を使用してクラスや名前によって要素を見つけることが可能になります。
  • USS クラスには BEM 規格 を使用します。これにより、全ての要素がクラスリストセレクターで扱えるようになります。
  • メモリフットプリントを小さくするために静的コールバックを使用します。コールバックとして使用するインスタンスメソッドを登録する時に、不要なアロケーションが発生することがあります。アロケーションを避けるには、通常の C# の静的メソッドを呼び出す匿名の静的ラムダ関数を使用します。EventBase.currentTarget プロパティで現在の要素のコンテキストを取得できます。

ヒント:

  • カスタムコントロールの generateVisualContent コールバックを使用してカスタムジオメトリをレンダリングします。部分的に塗りつぶされた円をレンダリングする使用例を、RadialProgress で参照できます。

  • カスタムコントロールは便利ですが、以下の方法でも同じ結果が得られる場合があります。

    • 既存の要素から UI を組み立て、そのスタイルやプロパティを変更します。
    • UXML テンプレートを使用します。通常の C# の MonoBehaviour を使用して、UI を保持する特定の UI ドキュメントに関連するロジックを追加します。(MonoBehaviour を使用して UI ドキュメントの UI を制御する方法については、ランタイム UI の作成に関するドキュメント を参照してください。) カプセル化を行うには、UQuery を使用して VisualElement を内部的にフェッチしてそれらのプロパティを操作するプロパティとメソッドを、MonoBehaviour 内に作成します。

その他の参考資料

カスタムコントロール
Expose custom control to UXML and UI Builder