美文网首页
Unity编辑器不影响原有布局拓展Inspector(转载)

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

作者: Boyce_Lig | 来源:发表于2022-03-21 10:47 被阅读0次

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

    [CustomEditor(typeof(RectTransform))]
    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)

    [CustomEditor(typeof(RectTransform))]
    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[0];
        
        #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[0]) 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[0]) 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[methodName] = method;
                }
                else
                {
                    Debug.LogError(string.Format("Could not find method {0}", method));
                }
            }
            else
            {
                method = decoratedMethods[methodName];
            }
            
            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)

    注:此方法有个弊端,不支持多选操作,多选时候写的面板会消失。

    相关文章

      网友评论

          本文标题:Unity编辑器不影响原有布局拓展Inspector(转载)

          本文链接:https://www.haomeiwen.com/subject/yiwzdrtx.html