您的位置:首页 > 移动开发 > Unity3D

Unity3D研究院编辑器之不影响原有布局拓展Inspector

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

1
2
3
4
5
6
7
8
9
10
11
12
13

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





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

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

这里有一个巧妙的反射方法,完美的解决这个问题。https://gist.github.com/liortal53/352fda2d01d339306e03

1
2
3
4
5
6
7
8
9
10
11
12
13

[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)如果你不确定可以去我反编译的代码里面去找。https://bitbucket.org/xuanyusong/unity-decompiled

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





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201

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

本文固定链接: http://www.xuanyusong.com/archives/3931

转载请注明: 雨松MOMO 2016年03月26日 于 雨松MOMO程序研究院 发表
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: