はじめに
こんにちは、アドベントカレンダー2日目担当の避雷です。お仕事でエディタ拡張する必要があり、たまたまバージョン的にもUIElementsが使える感じだったので試しに使ってみたところ結構便利だったので紹介します
- 基礎編(ここ)
- style編
UIElementsとは
Unityが公式でサポートしている新しいUIデザインの手法です。xamlやCSSと同様の記法によってUIのデザインができます。Unity的にはuGUIからこちらへの移行を試みているようで、uGUIの方はスタメンから外されてpackageManagerへの流刑を食らっています。主観としてはUnityはゲームエンジンからソフトウェア開発プラットフォームになろうとしていて、ゲーム以外のUI設計を可能にしたい、みたいなモチベなのかなと思いました。
https://blogs.unity3d.com/jp/2019/04/23/whats-new-with-uielements-in-2019-1/
メリット
- OnGUIコールバックベースからの脱却
- UIにeventを登録する感じでかけるので可読性が上がる。
- コードが書きやすい。
- xamlによってデザインするタイプの開発経験があると同じようなスタイルで触れる。
デメリット
- 必要になる技術が多い
- プロジェクトメンバー全員がxamlとかCSSとか触れるスキルセットじゃないと属人性がキツくなりがち
- 普通にuGUIの代替にはならないと思う
実装
導入
右クリックから「UIElements Editor Window」を選択して元となるスクリプトを生成しましょう。Editorフォルダ無いじゃないと生成出来ないよって怒られるので注意。
生成されるウィンドウを見てみよう
デフォルトだとWindow/UIElementから先ほど作成したwindowを呼び出すことができます。
HelloWorldって生成されていますね。
生成されたコードを読んでみよう
先ほど生成したC#を覗いてみましょう。
usingUnityEditor;usingUnityEngine;usingUnityEngine.UIElements;usingUnityEditor.UIElements;publicclassTest:EditorWindow{//メニューバーから呼び出すためのattribute[MenuItem("Window/UIElements/Test")]publicstaticvoidShowExample(){Testwnd=GetWindow<Test>();//↓タイトルの設定wnd.titleContent=newGUIContent("Test");}publicvoidOnEnable(){//rootVisualElement(表示されるUIすべての親となるVisualElementの取得)VisualElementroot=rootVisualElement;//VisualElementの一つ、ラベルを生成VisualElementlabel=newLabel("Hello World! From C#");//rootの子要素として追加、デフォルトだと子要素は上から下にstackされていくroot.Add(label);}}
なるほど、C#でもrootを根とした樹状構造を構築してUIを表現することが出来るみたいです。早速色々作ってみることにしましょう。
ラベルをつける
これに関してはそのままLabelというクラスがあるのでこれをインスタンスしてAppendして行きます。
Labellabel=newLabel("Hello World! From C#");root.Add(label);
コレでラベルを付けることが出来ます。label.text
を用いれば後からテキストの変更もできます。
Labellabel=newLabel("Hello World! From C#");root.Add(label);label.text="aa";
ボタンをつける
ButtonというクラスがあるのでこれもインスタンスしてAppendします。
Buttonbutton=newButton(()=>Debug.Log("aaa"));button.text="Button";root.Add(button);
Buttonコンストラクタの第一引数はイベントです。button.text
でボタンのテキストを変更することが出来ます。
入力ボックスを作る
TextFieldコンポネントを利用します。
TextFieldtextField=newTextField("textField");root.Add(textField);
入力された値を取るにはtextField.value
を用います。textField.RegisterValueChangedCallback
を用いて変更時のコールバックを設定することもできます。
textField.RegisterValueChangedCallback(x=>Debug.Log(x.previousValue+"=>"+x.newValue));
複数行入力に対応したいときは
textField.multiline
から入力形式を変更することが出来ます。ついでに style.height
から入力欄の高さを調整しておくとそれっぽいでしょう。
textField.multiline=true;//レイアウトにかかわる部分はXX.styleから変更できるtextField.style.height=50;
ドロップダウンを作る
PopUpListというクラスがあるのでそれを使いましょう。
List<string>choices=newList<string>(){"A","B","C"};PopupField<string>popupField=newPopupField<string>(choices,0);
コンストラクタの引数は第一が選択肢、第二が初期値です。
選択中のIdを取るには popupField.index
、選択中の値を取るにはpopupField.value
を用います。
また、TextField同様コールバックを登録することもできます。
popupField.RegisterValueChangedCallback(x=>Debug.Log(x.newValue));
VisualElementを使う
VisualElementはVisualElementを親として持つことが出来ます。Unityのオブジェクト群やCSS同様にヒエラルキー構造を持たせることが出来るということですね。
varelement=newVisualElement();
試しにmarginを設定してみます。
element.style.marginTop=10;element.style.marginBottom=10;element.style.marginLeft=10;element.style.marginRight=10;
ついでにborderLineも付けてみましょう
element.style.borderColor=newStyleColor(Color.black);element.style.borderBottomWidth=3;element.style.borderTopWidth=3;element.style.borderLeftWidth=3;element.style.borderRightWidth=3;
先ほどまで作っていたUIの親をrootではなくこのelementにしてみます。
// VisualElements objects can contain other VisualElement following a tree hierarchy.Labellabel=newLabel("Hello World! From C#");element.Add(label);label.text="aa";Buttonbutton=newButton(()=>Debug.Log("aaa"));button.text="Button";element.Add(button);TextFieldtextField=newTextField("textField");textField.RegisterValueChangedCallback(x=>Debug.Log(x.previousValue+"=>"+x.newValue));element.Add(textField);textField.multiline=true;textField.style.height=50;List<string>choices=newList<string>(){"A","B","C"};PopupField<string>popupField=newPopupField<string>(choices,0);element.Add(popupField);popupField.RegisterValueChangedCallback(x=>Debug.Log(x.newValue));root.Add(element);
親要素であるelementの中に子要素のUIが入っていることがわかると思います。
おわりに
コレでC#オンリーでも雑にUIを組めるようになったのではないでしょうか?明日はUIをもうちょっとマシなレイアウトで表示するための「style」について考えてみましょう。