|
今天无意间发现了一篇好文章,也让我解决了一个很久都没解决的难题。问题是这样的,假如我想去拓展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) |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|