UIToolKitUnityのUIElementsの基本的な使い方をまとめました。UIElementsとは?UIElementsを使ったエディタウィンドウを作成するUIの階層構造をUXMLファイルに分離するStyleを設定するStyleをUSSファイルに切り出す要素をスクリプトから取得して操作するUXMLの一部の要素をさらに別ファイルに分割するデータバインディングするIMGUIと組み合わせて使う見た目上の状態を保存するviewDataKeyInspector拡張にUIElementsを使う参考Unity2019.3.0UIElementsとは?UIElementsの概念を説明する上で、まずUnityでUIを組み立てる方法について振り返ります。UnityでUIを組み立てる方法には以下の3つがあります。IMGUIを使うuGUIを使うUIElementsを使うまずIMGUIは最も古い手法で、以下のようにソースコードベースでUIを組んでいきます。}}今日ではランタイムで使われることはほぼありませんが、エディタ拡張ではこれを使ってUIを組みます。uGUIを使うとヒエラルキーを使って直感的にUIを組めます。ランタイムのUIを構築するためには基本的にこれを使います。uGUIそしてUnity2019.1からUIElementsが登場しました。UIElementsはWebでよく用いられる、CSSとXMLを使ったUIの構築方法によく似た手法です。見た目の装飾にはUSSと呼ばれるスタイルシートを使い、階層構造の定義にはUXMLという形式を使います。UIElementsこの各ファイルにより責務が分離され、より複雑なUIがよりシンプルに組めるようになりました。エディタではIMGUIしか使えなかったので、これらすべてを同じcsファイルに書く必要があり複雑になりがちだったので、UIElementsの導入は大きなメリットがあるといえそうです。UIElementsは現時点ではエディタ用のUIにのみ使えますが、今後はランタイムのUIにも使用できるようにする方針のようです。IMGUIやuGUIに関しても引き続きメンテナンスは行われ、近い将来に廃止するという予定はないとのことです。UIElementsを使ったエディタウィンドウを作成するさてそれでは早速UIElementsを使ってみます。USSもUXMLも使わずに、ソースコードベースでエディタウィンドウを組んでみます。}}UnityEngine.UIElementsをusingすることで、BoxやButtonなどのUIElementsのUI要素を表すクラスが使えるようになります。上記のソースコードでは、Boxの中にButtonとLabelが入っているUIを組んでいます。描画結果UIの階層構造をUXMLファイルに分離する次にUIの階層構造の定義をUXMLファイルに分離していきます。Templateを選択します。下記のような内容のファイルが生成されるので、名前をuxml_exampleとして、Assets/Editor/Resources配下に配置しておきます。</engine:UXML>この自動生成のコードはテンプレなのでひとまずは理解しなくても大丈夫です。次にこのUXMLファイルを以下のように変更します。</engine:Box></engine:UXML>Boxの中にButtonとLabelを定義しています。prefixという名前空間を明示する機能です。今回の例では、Boxであれば本来はUnityEngine.UIElements:Boxと書かなければいけないところを、xmlns:engine="UnityEngine.UIElements"を定義することでengine:Boxと書けるようにしています。次にスクリプトを以下のように修正します。}}まずResources.Load<VisualTreeAsset>()で先ほど作ったUXMLファイルを読み込んでいます。AssetDatabaseで読み込んでもOKですが、配置場所の変更に弱くなるのでResourcesがおススメです。次にVisualTreeAsset.CloneTree()によりこの階層構造をウィンドウのUIとして適用しています。ウィンドウを開くと以下のように正常に表示されることが確認できます。表示Styleを設定するさて次にこれらのUI要素を装飾していきます。装飾するにはUXMLでstyle属性を指定します。</engine:Box></engine:UXML>コメントの通りですが、ここではBoxの横幅を200pxにしてLabelの色を赤くしました。ウィンドウを開きなおすと、以下のようにStyleが適用されていることが確認できます。Styleが適用されたStyleをUSSファイルに切り出す次に前節で設定したStyleを別のUSSファイルとして切り出します。FileからUSSファイルを作成します。uss_exampleと命名し、UXMLファイルと同様Assets/Editor/Resourcesフォルダ配下に格納します。ファイルの中身は以下のように書き換えます。red;}上記のコードにおいてexample_boxやexample_labelはStyleの名前を示し、中括弧内がスタイルの定義を表します。次にUXMLで各UIの要素とこのStyleを紐づけます。</engine:Box></engine:UXML>Styleを指定するには上記のようにclass属性を使います。他の方法もありますが、ひとまずclassを覚えておけばよいかと思います。最後に先ほど作ったUSSファイルをスクリプトから読み込みます。}スタイルシートはStyleSheet型でUSSファイルをロードすることで取得できます。取得したスタイルシートはVisualElement.styleSheeets.Add()で適用できます。ウィンドウを開きなおすと、以下のようにStyleが正常に適用されていることが確認できます。正常に適用されている要素をスクリプトから取得して操作する次に要素をスクリプトからコントロールしてみます。今回はボタンを取得して、クリック時のイベントを登録します。ボタンを取得するにはまずUXMLのname属性を使ってボタンに名前を付けます。</engine:Box></engine:UXML>次にこの名前を使ってスクリプトから呼び出します。}}UI要素を取得するにはVisualElement.Query<T>()を使います。取得後はLINQのようにして使えます。上記ソースコードの下部に書いたように、一つの要素だけを取得したい場合にはVisualElement.Q<T>()を使うと便利です。このウィンドウを開いてボタンを押下すると以下のようにログ出力されることが確認できます。ログ出力UXMLの一部の要素をさらに別ファイルに分割するここで、前節のUXMLのボタン部分をさらに別ファイルに分割してみます。このやり方を知っておくと、UIが複雑になってきたときに非常に便利です。新しくUXMLファイルを作成し、uxml_example_button.uxmlと命名します。これをAssets/Editor/Resourcesに配置して、中身を以下のように書き換えます。name="button01"/></engine:UXML>ボタンが一つ定義されているだけのUXMLファイルです。次にuxml_example.uxmlを以下のように書き換えます。</engine:Box></engine:UXML>上記ではまずTemplate要素を使うことで、ボタン用のUXMLファイルを読み込んでいます。このテンプレートにはname属性を使ってbutton-templateという名前を付けておきます。ボタンを配置したい場所でInstance要素のname属性にbutton-templateを指定することで、このテンプレートを展開します。ちなみに今回のようにTemplate要素のpath属性にUXMLファイル名を指定すると、Resourcesからそのファイルを探します。この場合には指定するファイル名に拡張子を付けてはいけないので注意してください。pathとは別にsrcという属性もあり、これを使うとプロジェクトまたはUXMLファイルからの相対パスでファイルを指定できます。src属性を使う場合には、pathとは異なりファイルパスに拡張子を付けないとエラーになるので注意が必要です。このウィンドウを開くと以下のように表示されます。正常に表示されていることが確認できました。データバインディングするここで、ボタンを押すたびにラベルのテキストが切り替わるようにしてみます。テキストが切り替わるこのようなケースではデータバインディングを使って、UI要素と変数を紐づけます。}データバインディングを行うにはまずバインドするためのシリアライズ可能な変数を定義します。VisualElement.Bind()を使うことでバインド処理を行います。UXML側にもこの変数名の情報を持たせておく必要があります。</engine:Box></engine:UXML>バインド対象の変数名をUXMLで指定するには上記のようにbinding-path属性を使います。ここまで実装したらウィンドウの挙動を確認してみます。ウィンドウ正常に変数がバインドされテキストが切り替わることが確認できました。IMGUIと組み合わせて使うUIElementsは従来のIMGUIと組み合わせて使うこともできます。IMGUIと組み合わせるには、以下のようにIMGUIContainerクラスを使用します。}}IMGUIContainerはVisualElementを継承しているクラスなので、上記のようにこれを他のVisualElementにAddすればOKです。見た目上の状態を保存するviewDataKeyさて、UIElementのFoldoutクラスを使うと以下のように折り畳みのビューが表示できます。折り畳みここで、コンパイルが走ったりエディタを再起動したりするとこのビューの折り畳み状態がリセットされてしまいます。この折り畳み状態やスクロール位置など、ビューだけに関わる状態を保持したい場合にはUIElement.viewDataKeyを使います。}上記のようにVisualElement.viewDataKeyに任意の文字列を入れておくことで、それをキーにして状態が保持されます。コンパイルを走らせたりエディタを再起動しても下図のように折り畳み状態が保持されていることが確認できました。状態が保持Inspector拡張にUIElementsを使うここまではEditorWindowに対してUIElementを使う方法を紹介してきましたが、UIElementsはInspectorの拡張にも使えます。Inspector拡張に使うには従来のEditor.OnInspectorGUI()ではなくEditor.CreateInspectorGUI()をオーバーライドします。}}CreateInspectorGUIの中ではVisualElementをnewして、そこにVisualElementをAddしていきます。上記のソースコードを適用すると以下のようなInspector表示になります。Inspector正常にInspectorが拡張できていることを確認できました。1はてなブログをはじめよう!halya_11さんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。