[轉(zhuǎn)]Unity3D研究院編輯器之不影響原有布局拓展Inspector

今天無意間發(fā)現(xiàn)了一篇好文章蹭秋,也讓我解決了一個很久都沒解決的難題蹋凝。問題是這樣的脐瑰,假如我想去拓展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面板的下面去添加一個按鈕魄衅,可是我一旦調(diào)用base.OnInspectorGUI()方法以后,原有的布局都就變了塘辅。

為什么會影響到原有布局呢晃虫?原因是這樣的上面的代碼是繼承Editor的,那么base.OnInspectorGUI()實(shí)際上去掉用了Editor類里的OnInspectorGUI()方法扣墩,可是RectTransfm的OnInspectorGUI()方法是在RectTransformEditor這個類寫的哲银。

但是問題就來了,RectTransformEditor這個類不是一個對外公開的類呻惕。所以不能繼承它荆责,那也就無法調(diào)用它的OnInspectorGUI()方法了,所以就有了上述問題亚脆。

這里有一個巧妙的反射方法做院,完美的解決這個問題。https://gist.github.com/liortal53/352fda2d01d339306e03

[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

如下圖所示柑营,現(xiàn)在既保留了原有的布局屈雄,也可以方便的拓展了。官套。

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 ();
    }
}

本文轉(zhuǎn)載自:http://www.xuanyusong.com/archives/3931

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酒奶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子奶赔,更是在濱河造成了極大的恐慌惋嚎,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺阔,死亡現(xiàn)場離奇詭異瘸彤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)笛钝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門质况,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玻靡,你說我怎么就攤上這事结榄。” “怎么了囤捻?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵臼朗,是天一觀的道長。 經(jīng)常有香客問我蝎土,道長视哑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任誊涯,我火速辦了婚禮挡毅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘暴构。我一直安慰自己跪呈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布取逾。 她就那樣靜靜地躺著耗绿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砾隅。 梳的紋絲不亂的頭發(fā)上误阻,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機(jī)與錄音晴埂,去河邊找鬼堕绩。 笑死,一個胖子當(dāng)著我的面吹牛邑时,可吹牛的內(nèi)容都是我干的奴紧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼晶丘,長吁一口氣:“原來是場噩夢啊……” “哼黍氮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起浅浮,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤沫浆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后滚秩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體专执,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年郁油,在試婚紗的時候發(fā)現(xiàn)自己被綠了本股。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攀痊。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拄显,靈堂內(nèi)的尸體忽然破棺而出苟径,到底是詐尸還是另有隱情,我是刑警寧澤躬审,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布棘街,位于F島的核電站,受9級特大地震影響承边,放射性物質(zhì)發(fā)生泄漏遭殉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一博助、第九天 我趴在偏房一處隱蔽的房頂上張望险污。 院中可真熱鬧,春花似錦翔始、人聲如沸罗心。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽渤闷。三九已至,卻和暖如春脖镀,著一層夾襖步出監(jiān)牢的瞬間飒箭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工蜒灰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弦蹂,地道東北人。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓强窖,卻偏偏與公主長得像凸椿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子翅溺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容