開發 Unity3D 時, 是否經常在訂製 Editor, 希望為其中某些 SerializedProperty 部分做自訂, 但因為一開始訂製又需要整個 component 上的所有顯示的參數也需要訂製而覺得頭痛??!
其實如果簡單的取代某幾個 property 的繪製是可行的,
只需要以下的寫法即可.
public override void OnInspectorGUI()
{
serializedObject.Update();
SerializedProperty iter = serializedObject.GetIterator();
iter.NextVisible(true); // enter children.
EditorGUI.BeginChangeCheck(); // ---- change check [optional]
do
{
// draw element & it's children
EditorGUILayout.PropertyField(iter, includeChildren: true);
}
while (iter.NextVisible(false));
if (EditorGUI.EndChangeCheck()) // ---- change check [optional]
serializedObject.ApplyModifiedProperties();
}
這一段的寫法其實跟原本的
base.OnInspectorGUI();
就結果上完全沒有分別… 那麼為甚麼要這樣寫呢?!
原因
- 可以保留在 Class 中宣告參數的順序
- 可以保留一些特殊 attribute 如 [Header] [Range] 等這些繪製宣告
- 可以單獨的對某個 property 進行額外加插的自訂方式 (後文述)
- 可擴充性彈性, 基類的參數中, 沒有被指定的可以隨意增減修改, 而不需要重寫 Editor.
這裡提供一些變體用法, 跟 OnEnable 配搭可以輕易的取得當下繪製的 property, 是否自己希望修改的一員, 而作出相對應的取代.
SerializedProperty propA, propB;
private void OnEnable()
{
propA = serializedObject.FindProperty("m_A");
propB = serializedObject.FindProperty("m_B");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
SerializedProperty iter = serializedObject.GetIterator();
iter.NextVisible(true); // enter children.
EditorGUI.BeginChangeCheck(); // ---- change check [optional]
do
{
if (iter.propertyPath == propA.propertyPath)
{
// Special setup for A
// if (Application.isPlaying) {...} else {....}
}
else if (iter.propertyPath == propB.propertyPath)
{
// Special setup for B
EditorGUILayout.PropertyField(iter, includeChildren: true);
EditorGUILayout.HelpBox("more info !!!", MessageType.Info);
}
else
{
// draw element & it's children
EditorGUILayout.PropertyField(iter, includeChildren: true);
}
}
while (iter.NextVisible(false));
if (EditorGUI.EndChangeCheck()) // ---- change check [optional]
serializedObject.ApplyModifiedProperties();
}
期待有更多的玩法, 歡迎討論.