はじめに
上記の記事の最後にある
あと実は紹介した DefaultEditor の実装にも問題があり、一番上に描画されるスクリプトの PropertyField をクリックしてもスクリプトファイルがpingされない問題があるのですが、それについてはまた別の記事で書こうと思います。
これについてです。
環境
- Unity2021.3.0f1
Unity2022.1.0f1(Apple Silicon版)では再現しなかったので修正されたようです。
UI Toolkitを使ったときのInspectorの問題
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[CustomEditor(typeof(SampleComponent), true)]
public class SampleComponentEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var container = new VisualElement();
// IMGUI同様のInspectorを実装
InspectorElement.FillDefaultInspector(container, serializedObject, this);
return container;
}
}
#endif
これで描画されるInspectorではスクリプトの名前のところをクリックしてもスクリプトがpingされません。
上が通常のデフォルトエディタ (クリックでpingされる)
下が UI Toolkit を使ったカスタムエディタ (pingされない)
解決方法: PropertyField
の代わりに ObjectField
をカスタムして使う
この問題については以下のフォーラムの投稿が参考になります。
以下コード引用。
private static VisualElement CreateScriptReadonlyField(SerializedProperty property)
{
VisualElement propertyField = new VisualElement() { name = $"PropertyField:{property.propertyPath}" };
ObjectField objectField = new ObjectField("Script") { name = "unity-input-m_Script" };
objectField.BindProperty(property);
propertyField.Add(objectField);
propertyField.Q(null, "unity-object-field__selector")?.SetEnabled(false);
propertyField.Q(null, "unity-base-field__label")?.AddToClassList("unity-disabled");
propertyField.Q(null, "unity-base-field__input")?.AddToClassList("unity-disabled");
return propertyField;
}
SetEnabled(false)
で右側のボタンを無効にしているのと、 AddToClassList("unity-disabled")
でdisabled状態のスタイルシートを適用しています。
PropertyField
だと CreateInspectorGUI()
の時点で要素にアクセスできない(自分もこれで悩んだ)ので、 ObjectField
の代わりに PropertyField
を使うようです。
*****
上記を参考に、スクリプトのpingも可能なデフォルトのカスタムエディタを書くとこんな感じです。
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
[CustomEditor(typeof(Object), true, isFallback = true)]
public class DefaultEditor : Editor
{
private static VisualElement CreateScriptReadonlyField(SerializedProperty property)
{
var propertyField = new VisualElement { name = $"PropertyField:{property.propertyPath}" };
var objectField = new ObjectField("Script") { name = "unity-input-m_Script" };
objectField.BindProperty(property);
// スペースキーを押してもスクリプトを選択するウィンドウを表示しないようにする
objectField.focusable = false;
propertyField.Add(objectField);
propertyField.Q(null, "unity-object-field__selector")?.SetEnabled(false);
propertyField.Q(null, "unity-base-field__label")?.AddToClassList("unity-disabled");
propertyField.Q(null, "unity-base-field__input")?.AddToClassList("unity-disabled");
return propertyField;
}
public override VisualElement CreateInspectorGUI()
{
var container = new VisualElement();
var iterator = serializedObject.GetIterator();
if (iterator.NextVisible(true))
{
do
{
var serializedProperty = iterator.Copy();
VisualElement propertyField;
if (iterator.propertyPath == "m_Script" && serializedObject.targetObject != null)
{
propertyField = CreateScriptReadonlyField(serializedProperty);
}
else
{
propertyField = new PropertyField(iterator.Copy()) { name = "PropertyField:" + iterator.propertyPath };
}
container.Add(propertyField);
}
while (iterator.NextVisible(false));
}
return container;
}
}
#endif
元のコードだとフォーカスが当たってるときに Space
キーを押すとスクリプトを選択するウィンドウが表示されてしまうので、
objectField.focusable = false;
を入れてあります。
雑感
件の投稿は「こんな実装してみたけど問題ない?」という感じの内容なのですが、まじめにやろうと思ったら BaseField<UnityEngine.Object>
を継承してクラスを手実装する必要がありそうです。
でもまぁUnityのバージョン上げれば解決される問題だし、これでいいかなという感じ。