【Unity2019】UIElementsを触ってみた
本記事は、サムザップ Advent Calendar 2019 #2 の12/23の記事です。
Unity2019.1新機能「UIElements」とは
IMGUIからUIElementsに置き換わるであろう新しいGUIシステムです。
UIElementsはUXML/USS/UQueryで構成されます。
所感、
UXMLはUnityで扱えるXMLベースのマークアップ言語のイメージ
USSはCSSに近い書き方でデザインが出来そう
UQueryはC#で主にロジック部分を書くのかな…
って感じでした。
Unity Blog「Unity 2019.1 の UIElements の新機能」
テキスト読んだだけじゃ頭に入ってこないので、取り敢えず触ってみよう。。
「UIElements」を触ってみる
開発環境
今回使用する環境はUnity2019.3.0f1
です。
(普段Unity2018のLTS版触っているから、Editorの見た目に違和感…w)
「UIElements」をHelloWorld
1.「UIElements」のEditorWindowを開く
右クリックでメニュー開く > [Create] > [UIElements] > [Editor Window]
もしくは
[Assets] > [Create] > [UIElements] > [Editor Window]
2.「UIElements」EditorWindowで作成
3.準備完了
作成されたデフォルトの中身
DefaultUIElementsEditorWindow.cs
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
public class DefaultUIElementsEditorWindow : EditorWindow
{
[MenuItem("Window/UIElements/DefaultUIElementsEditorWindow")]
public static void ShowExample()
{
DefaultUIElementsEditorWindow wnd = GetWindow<DefaultUIElementsEditorWindow>();
wnd.titleContent = new GUIContent("DefaultUIElementsEditorWindow");
}
public void OnEnable()
{
// Each editor window contains a root VisualElement object
VisualElement root = rootVisualElement;
// VisualElements objects can contain other VisualElement following a tree hierarchy.
VisualElement label = new Label("Hello World! From C#");
root.Add(label);
// Import UXML
var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/Editor/DefaultUIElementsEditorWindow.uxml");
VisualElement labelFromUXML = visualTree.CloneTree();
root.Add(labelFromUXML);
// A stylesheet can be added to a VisualElement.
// The style will be applied to the VisualElement and all of its children.
var styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/DefaultUIElementsEditorWindow.uss");
VisualElement labelWithStyle = new Label("Hello World! With Style");
labelWithStyle.styleSheets.Add(styleSheet);
root.Add(labelWithStyle);
}
}
DefaultUIElementsEditorWindow.uxml
<?xml version="1.0" encoding="utf-8"?>
<engine:UXML
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:engine="UnityEngine.UIElements"
xmlns:editor="UnityEditor.UIElements"
xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
>
<engine:Label text="Hello World! From UXML" />
</engine:UXML>
DefaultUIElementsEditorWindow.uss
Label {
font-size: 20px;
-unity-font-style: bold;
color: rgb(68, 138, 255);
}
つまづきポイント
「UIElements」のEditorWindowでエラー
下記のようなエラーが発生した(何起因で発生したかは分からない…)
対処法
Editorフォルダ配下で
右クリックでメニュー開く > [Update UIElements Schema]
もしくは
[Assets] > [Update UIElements Schema]
UXMLのタグ頭に「engine:」を付けないとエラー
Unity公式のリファレンスでは「engine:」がタグ頭に付いてる例と付いていない例がある。毎回「engine:」をタグ頭につけるような冗長な書き方は避けたいけど、「engine:」を失くすとエラーになる。。
対処法
デフォルトで生成されるUXMLは下記のようにnamespaceが指定されているので、毎回「engine:」をタグ頭につける必要があったっぽい
xmlns:engine="UnityEngine.UIElements"
下記のようにnamespaceを失くすことで、毎回「engine:」をタグ頭に付けなくても良くなる。
※必要な時にnamespaceで区切ろうかな…
xmlns="UnityEngine.UIElements"
軽く基盤を作ってみる
built-inのHelloWorldファイルは色々イケてない
- UXML内に既にnamespaceが指定されている
- USSがLabelにしか適用されない
ってことで、
とりあえず、複数のUXMLとUSSをデータとして受け取ったら、それを使ってEditorWindowを構築してくれるものが欲しい
試しに作ってみる
コレで、基盤のEditorWindowクラスが設定データを元に構築してくれる。
実際の基盤クラス
EditorWindowのデータクラス
using UnityEngine;
using UnityEngine.UIElements;
namespace System.Common.Editor.Window
{
/// <summary>
/// エディタウィンドウのデータの設定クラス
/// </summary>
[CreateAssetMenu(fileName = "EditorWindowSettingData", menuName = "Tools/Editor Window/Create Setting Data/EditorWindowData")]
public class EditorWindowData : ScriptableObject
{
/// <summary>
/// UXML一覧
/// </summary>
[SerializeField]
private VisualTreeAsset[] uxmlArray;
public VisualTreeAsset[] UxmlArray { get => uxmlArray; }
/// <summary>
/// USS一覧
/// </summary>
[SerializeField]
private StyleSheet[] ussArray;
public StyleSheet[] UssArray { get => ussArray; }
}
}
EditorWindowのBaseクラス
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace System.Common.Editor.Window
{
/// <summary>
/// エディタウィンドウのベースクラス
/// </summary>
public class EditorWindowBase<T> : EditorWindow where T : EditorWindow
{
/// <summary>
/// 設定データ
/// </summary>
[SerializeField]
private EditorWindowData editorSettingData;
private static T _instance;
public static T Instance { get => _instance; private set => _instance = value; }
/// <summary>
/// Window開く
/// </summary>
public static void Open()
{
Instance = GetWindow<T>();
Instance.titleContent = new GUIContent(Instance.GetType().Name);
}
/// <summary>
/// アクティブ処理
/// </summary>
protected virtual void OnEnable() { Init(); }
/// <summary>
/// 非アクティブ処理
/// </summary>
protected virtual void OnDisable() { Disable(); }
/// <summary>
/// 初期化
/// </summary>
protected virtual void Init()
{
if (editorSettingData == null)
return;
// Each editor window contains a root VisualElement object
VisualElement root = rootVisualElement;
if (root == null)
return;
// Import UXML
foreach (var uxml in editorSettingData.UxmlArray)
{
if (uxml == null)
continue;
root.Add(uxml.CloneTree());
}
// Import USS
foreach (var uss in editorSettingData.UssArray)
{
if (uss == null)
continue;
root.styleSheets.Add(uss);
}
}
/// <summary>
/// 停止処理
/// </summary>
protected virtual void Disable() { }
}
}
テストデータ
EditorWindowの呼び出し口(TestEditorWindowを開くだけ)
using UnityEditor;
using Test.Editor.Window;
namespace Tools
{
public class ToolMenu
{
[MenuItem("Tools/Editor Window/TestWindow")]
public static void Open() { TestEditorWindow.Open(); }
}
}
EditorWindow(中身なし)
using System.Common.Editor.Window;
namespace Test.Editor.Window
{
public class TestEditorWindow : EditorWindowBase<TestEditorWindow>
{
}
}
UXML(中身なし)
<?xml version="1.0" encoding="utf-8"?>
<UXML
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="UnityEngine.UIElements"
xsi:noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd"
>
</UXML>
参考にしたリファレンス
UIElements Developer Guide
https://docs.unity3d.com/Manual/UIElements.html
UXML関連
https://docs.unity3d.com/Manual/UIE-ElementRef.html
触ってみて…
IMGUIよりUIElementsの方が、Viewと処理を分けられるから読みやすそう。(小規模なツールはIMGUIの方が書きやすそうだけど…)
でも、毎回タグ頭に「engine:」をつけるのはダルいので、UXML内の対応で回避してみた。
UXMLのテンプレートを用意したり、SerializeField表示のためにBindして表示できるようにしたりと、基盤としてやらなきゃいけないことは結構あるけど、、、
って、今見たらVisualElement
にBind
がなさそう…
visualElement.Bind(serializedData);
的な感じで行けると思ったんだけど…
SerializeField表示方法をまた調べなきゃ…笑
Assetsと同階層のUIElementsSchemaディレクトリにUIElements.xsdとか色々定義されていたので、CustomしたXMLSchemaを作ってみるのをどっかで試してみたい。
明日は @m-nakayama さんの記事です。
Author And Source
この問題について(【Unity2019】UIElementsを触ってみた), 我々は、より多くの情報をここで見つけました https://qiita.com/kida_hironari/items/19cf3bc913a9c1e9da4c著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .