pc8888888 发表于 2022-3-26 21:06

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()方法以后,原有的布局都就变了


image.png

为什么会影响到原有布局呢?原因是这样的上面的代码是继承Editor的,那么base.OnInspectorGUI()实际上去掉用了Editor类里的OnInspectorGUI()方法,可是RectTransfm的OnInspectorGUI()方法是在RectTransformEditor这个类写的。

但是问题就来了,RectTransformEditor这个类不是一个对外公开的类。所以不能继承它,那也就无法调用它的OnInspectorGUI()方法了,所以就有了上述问题。

这里有一个巧妙的反射方法,完美的解决这个问题。Extend Unity's built-in inspectors (github.com)
public class MyTest : DecoratorEditor{    public MyTest(): base("RectTransformEditor"){}    public override void OnInspectorGUI ()    {      base.OnInspectorGUI ();      if(GUILayout.Button("Adding this button"))      {            Debug.Log("Adding this button");      }    }}
理论上unity提供的每一个脚本都有一个 XXXEditor 类 , 用来绘制它的面板。(本文用到的就是 RectTransformEditor)如果你不确定可以去我反编译的代码里面去找。xuanyusong / unity-decompiled — Bitbucket

如下图所示,现在既保留了原有的布局,也可以方便的拓展了。。


image.png

using System.Collections.Generic;using System.Linq;using System.Reflection;using UnityEditor;using UnityEngine; /// <summary>/// A base class for creating editors that decorate Unity'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(转载)