ReorderableListとPropertyDrawerを組み合わせて使う
たびたびですがちょびえです。今日はReorderableListとPropertyDrawerの組み合わせで悩んでしまったのでまた書いときます。
UnityEditorで並び替えできるリストが欲しい
となると、あまり説明がされていないReorderableListをつかうのがとても良い感じです。が海外でも日本でもReorderableListとPropertyDrawerの組み合わせって
分かりやすい解説がなくこんがらがりがちです。御多分にもれずハマってしまったので忘れないように書いときます。
PropertyDrawer
PropertyDrawerはSystem.SerializableのAttributeを付けたPrimitiveやクラスなどをいい感じに表示してくれる機能です。
カスタムInspectorはComponentと対、カスタムPropertyDrawerはプロパティやフィールドと対になっています。
例えば、PersonDataというクラスがあるとして、PropertyDrawerをカスタムしたい場合は下記のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
using System; using UnityEngine; [Serializable] public class PersonData { public string Name; public int Age; public override string ToString() { return string.Format("{0} {1}", Name, Age); } } |
AddressbookというMonobehaviourを継承したクラスを作成し、PersonDataをもたせてみます
1 2 3 4 5 6 7 8 |
using UnityEngine; using System.Collections; public class Addressbook : MonoBehaviour { [SerializeField] PersonData data; } |
この状態でGameObjectにアタッチすると、このような表示になります。
この場合そのままでも十分見やすい状態なのですが、PropertyDrawerを使ってdataフィールドの表示を変更してみたいと思います。
下記スクリプトをEditor/PersonDataDrawer.csという名前で保存して再読み込みをしてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using UnityEngine; using System.Collections; using UnityEditor; [CustomPropertyDrawer(typeof (PersonData))] public class PersonDataDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { //とりあえずlabelなしで半分にした入力フィールドをつくる position.width *= 0.5f; EditorGUI.PropertyField(position, property.FindPropertyRelative("Name"), GUIContent.none); position.x += position.width; EditorGUI.PropertyField(position, property.FindPropertyRelative("Age"), GUIContent.none); } } |
このように、dataフィールドのInspectorでの見た目をカスタムすることができました。
今回の場合、もともとの状態のほうが見やすいのですが自前でカスタムすることができる、というのがわかればOKです。
ReorderableListと組み合わせしてみる
ReorderableListはMecanimなどのPriority変更などで使われているUI部分です。順番が重要なリストをInspector上で変更したい場合はReorderableListを使うのが
現実的な手段だと思います。
Addressbookのカスタムインスペクターを作成し、自前でAddressbookのInspectorを描画できるようにします。
下記スクリプトをEditor/AddressbookInspector.csで保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using UnityEngine; using UnityEditor; using UnityEditorInternal; [CustomEditor(typeof(Addressbook))] public class AddressbookInspector : Editor { private ReorderableList reorderableList; void OnEnable() { //SerializedObjectからdata(Addressbook.data)を取得し、ReordableListを作成する reorderableList = new ReorderableList(serializedObject, serializedObject.FindProperty("data")); reorderableList.drawElementCallback += (Rect rect, int index, bool selected, bool focused) => { SerializedProperty property = reorderableList.serializedProperty.GetArrayElementAtIndex(index); // PropertyFieldを使ってよしなにプロパティの描画を行う(PersonDataはPropertyDrawerを使っているのでそちらに移譲されます) EditorGUI.PropertyField(rect, property, GUIContent.none); }; reorderableList.drawHeaderCallback += rect => { EditorGUI.LabelField(rect, "Addressbok:"); }; } public override void OnInspectorGUI() { // 自前で描画している部分。ApplyModifiedPropertiesも忘れずに! reorderableList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } } |
ついでにAddressbook.csのPersonDataもReordableListで扱いやすいように配列にしておきましょう。
1 2 3 4 5 6 7 8 9 |
using UnityEngine; using System.Collections; public class Addressbook : MonoBehaviour { [SerializeField] PersonData[] data; } |
この状態で最新の状態にするとInspectorが次のような表示になります。
右下の+ボタンを押すことで行を追加することができます。
ReordableListへのイベント追加、登録が若干適当ではありますがまぁまぁ、、、、うごいているので良しとしましょう。
実際に使う場合はReordableListのイベントを正しく設定してください。ドキュメントに記載がありませんが、安藤さんのUnityEditor拡張に詳しく記載あったり、下記ページにイベントについて書いてあったりします。
Fixed-width labels for fields in Unity3D Editor GUI - Firtoz
Why?
Unity3D's default GUI system has dynamic label width. This ensures that the input boxes start at the same position. It can results in problems in spe…
まとめ
簡単ではありますが、ReorderableListとPropertyDrawerを組み合わせた場合のやり方についてまとめました。
primitiveな配列以外を保存したり、描画しようとするとカスタムインスペクター+drawElementCallbackだとかなりつらい感じになってしまうので
PropertyDrawerを作成して利用するのが作り方的にもやりやすいかと思います。
ではでは。