zhln9988 发表于 2024-7-15 17:55

Unity编纂器不影响原有布局拓展Inspector(转载)

今天无意间发现了一篇好文章,也让我解决了一个很久都没解决的难题。问题是这样的,假如我想去拓展Unity自带的inspector但是并不想影响原有布局。 比如下面这段代码:

public class MyTest : Editor
{
    public override void OnInspectorGUI ()
    {
      base.OnInspectorGUI ();
      if(GUILayout.Button(”Adding this button”))
      {
            Debug.Log(”Adding this button”);
      }
    }
}我的本意是想在Rect Transform面板的下面去添加一个按钮,可是我一旦调用base.OnInspectorGUI()方式以后,原有的布局都就变了


为什么会影响到原有布局呢?原因是这样的上面的代码是担任Editor的,那么base.OnInspectorGUI()实际上去掉用了Editor类里的OnInspectorGUI()方式,可是RectTransfm的OnInspectorGUI()方式是在RectTransformEditor这个类写的。
但是问题就来了,RectTransformEditor这个类不是一个对外公开的类。所以不能担任它,那也就无法调用它的OnInspectorGUI()方式了,所以就有了上述问题。
这里有一个巧妙的反射方式,完美的解决这个问题。Extend Unity's built-in inspectors (GitHub: Where the world builds software)
理论上unity提供的每一个脚本都有一个 XXXEditor 类 , 用来绘制它的面板。(本文用到的就是 RectTransformEditor)如果你不确定可以去我反编译的代码里面去找。xuanyusong / unity-decompiled — Bitbucket
如下图所示,此刻既保留了原有的布局,也可以便利的拓展了。。


using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

/// <summary>
/// A base class for creating editors that decorate Unity&#39;s built-in editor types.
/// </summary>
public abstract class DecoratorEditor : Editor
{
    // empty array for invoking methods using reflection
    private static readonly object[] EMPTY_ARRAY = new object;
   
    #region Editor Fields
   
    /// <summary>
    /// Type object for the internally used (decorated) editor.
    /// </summary>
    private System.Type decoratedEditorType;
   
    /// <summary>
    /// Type object for the object that is edited by this editor.
    /// </summary>
    private System.Type editedObjectType;
   
    private Editor editorInstance;
   
    #endregion

    private static Dictionary<string, MethodInfo> decoratedMethods = new Dictionary<string, MethodInfo>();
   
    private static Assembly editorAssembly = Assembly.GetAssembly(typeof(Editor));
   
    protected Editor EditorInstance
    {
      get
      {
            if (editorInstance == null && targets != null && targets.Length > 0)
            {
                editorInstance = Editor.CreateEditor(targets, decoratedEditorType);
            }
            
            if (editorInstance == null)
            {
                Debug.LogError(”Could not create editor !”);
            }
            
            return editorInstance;
      }
    }
   
    public DecoratorEditor (string editorTypeName)
    {
      this.decoratedEditorType = editorAssembly.GetTypes().Where(t => t.Name == editorTypeName).FirstOrDefault();
      
      Init ();
      
      // Check CustomEditor types.
      var originalEditedType = GetCustomEditorType(decoratedEditorType);
      
      if (originalEditedType != editedObjectType)
      {
            throw new System.ArgumentException(
                string.Format(”Type {0} does not match the editor {1} type {2}”,
                        editedObjectType, editorTypeName, originalEditedType));
      }
    }
   
    private System.Type GetCustomEditorType(System.Type type)
    {
      var flags = BindingFlags.NonPublic| BindingFlags.Instance;
      
      var attributes = type.GetCustomAttributes(typeof(CustomEditor), true) as CustomEditor[];
      var field = attributes.Select(editor => editor.GetType().GetField(”m_InspectedType”, flags)).First();
      
      return field.GetValue(attributes) as System.Type;
    }
   
    private void Init()
    {      
      var flags = BindingFlags.NonPublic| BindingFlags.Instance;
      
      var attributes = this.GetType().GetCustomAttributes(typeof(CustomEditor), true) as CustomEditor[];
      var field = attributes.Select(editor => editor.GetType().GetField(”m_InspectedType”, flags)).First();
      
      editedObjectType = field.GetValue(attributes) as System.Type;
    }

    void OnDisable()
    {
      if (editorInstance != null)
      {
            DestroyImmediate(editorInstance);
      }
    }
   
    /// <summary>
    /// Delegates a method call with the given name to the decorated editor instance.
    /// </summary>
    protected void CallInspectorMethod(string methodName)
    {
      MethodInfo method = null;
      
      // Add MethodInfo to cache
      if (!decoratedMethods.ContainsKey(methodName))
      {
            var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
            
            method = decoratedEditorType.GetMethod(methodName, flags);
            
            if (method != null)
            {
                decoratedMethods = method;
            }
            else
            {
                Debug.LogError(string.Format(”Could not find method {0}”, method));
            }
      }
      else
      {
            method = decoratedMethods;
      }
      
      if (method != null)
      {
            method.Invoke(EditorInstance, EMPTY_ARRAY);
      }
    }

    public void OnSceneGUI()
    {
      CallInspectorMethod(”OnSceneGUI”);
    }

    protected override void OnHeaderGUI ()
    {
      CallInspectorMethod(”OnHeaderGUI”);
    }
   
    public override void OnInspectorGUI ()
    {
      EditorInstance.OnInspectorGUI();
    }
   
    public override void DrawPreview (Rect previewArea)
    {
      EditorInstance.DrawPreview (previewArea);
    }
   
    public override string GetInfoString ()
    {
      return EditorInstance.GetInfoString ();
    }
   
    public override GUIContent GetPreviewTitle ()
    {
      return EditorInstance.GetPreviewTitle();
    }
   
    public override bool HasPreviewGUI ()
    {
      return EditorInstance.HasPreviewGUI ();
    }
   
    public override void OnInteractivePreviewGUI (Rect r, GUIStyle background)
    {
      EditorInstance.OnInteractivePreviewGUI (r, background);
    }
   
    public override void OnPreviewGUI (Rect r, GUIStyle background)
    {
      EditorInstance.OnPreviewGUI (r, background);
    }
   
    public override void OnPreviewSettings ()
    {
      EditorInstance.OnPreviewSettings ();
    }
   
    public override void ReloadPreviewInstances ()
    {
      EditorInstance.ReloadPreviewInstances ();
    }
   
    public override Texture2D RenderStaticPreview (string assetPath, Object[] subAssets, int width, int height)
    {
      return EditorInstance.RenderStaticPreview (assetPath, subAssets, width, height);
    }
   
    public override bool RequiresConstantRepaint ()
    {
      return EditorInstance.RequiresConstantRepaint ();
    }
   
    public override bool UseDefaultMargins ()
    {
      return EditorInstance.UseDefaultMargins ();
    }
}版本: Unity5.3.3
转载链接:Unity3D研究院编纂器之不影响原有布局拓展Inspector(二十四) | 雨松MOMO法式研究院 (xuanyusong.com)
注:此方式有个短处,不撑持多选操作,多选时候写的面板会消掉。
页: [1]
查看完整版本: Unity编纂器不影响原有布局拓展Inspector(转载)