对于检视面板 Inspector 的面板继承方式对项目来说是很有必要的, 比如一个基类, 写了一个很好看的检视面板[CustomEditor(typeof(XXX))],

可是所有子类的面板无法直接继承这个CustomEditor, 有些人的解决方案是把子类写检视面板的代码独立出来, 然后子类面板直接去调用这些Layout,

非常浪费人力物力.

  最近发现有个 DecoratorEditor 脚本, 它实现了对 Unity 自带检视面板的扩展, 看到它实现某个类型的面板Inspector的方法, 就是使用Editor.CreateEditor 这个API

创建了一个相应的Editor, 然后调用它的OnInspectorGUI() 方法来绘制原有面板的, 于是可以从这个地方着手.

  从设计上来说 [CustomEditor(typeof(XXX))] 在耦合上并没有太多的耦合, Unity 开发组的想法应该就是一个Editor对应一个组件, 它们对应类型之间的继承关系不应该

互相影响, 保证泛用性和独立性.

  原始的Editor脚本和类型是这样的:

基类 :

public class TestBaseClass : MonoBehaviour
{public float abc;
}// 检视面板
[CustomEditor(typeof(TestBaseClass))]
public class TestBaseClassInspector : Editor
{TestBaseClass _target;private void OnEnable(){_target = target as TestBaseClass;}public override void OnInspectorGUI(){_target.abc = EditorGUILayout.FloatField("基类变量 : ", _target.abc);}
}

子类1 :

public class TestCamera : TestBaseClass
{public Camera cam;
}// 检视面板
[CustomEditor(typeof(TestCamera))]
public class TestCameraInspector : Editor
{TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.cam = EditorGUILayout.ObjectField("一次继承变量 : ", _target.cam, typeof(Camera), true) as Camera;}
}

子类2 :

public class TestUntiy : TestCamera
{public int hahah;
}// 检视面板
[CustomEditor(typeof(TestUntiy))]
public class TestUntiyInspector : Editor
{TestUntiy _target = null;private void OnEnable(){_target = target as TestUntiy;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.hahah = EditorGUILayout.IntField("二次继承变量 : ", _target.hahah);}
}

  

TestBaseClass
TestCamera : TestBaseClass
TestUntiy : TestCamera

非常简单的继承关系, TestUnity的检视面板如下, 没有继承关系

  那么在继承的设计上, 也应该遵循Unity的设计原则, 在继承类型 : Editor 以及 base.OnInspectorGUI(); 绘制基类方法上做文章.

如果使用简单的继承比如:

[CustomEditor(typeof(TestCamera))]
public class TestCameraInspector : TestBaseClassInspector
{TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){base.OnInspectorGUI();_target.cam = EditorGUILayout.ObjectField("一次继承变量 : ", _target.cam, typeof(Camera), true) as Camera;}
}

  会出现很多问题, 如基类的OnEnable方法没有被触发, 基类面板报错等, 所有生命周期都要写虚方法, 每个重写方法都要注意, 很麻烦.

  而Editor.CreateEditor创建的Editor是有生命周期的. 创建一个中间类型 InspectorDecoratorEditor, 大家都继承它就可以了, 而绘制基类对象的方法就改为

DrawBaseInspectorGUI<T>(), 这样就能方便地自己定义需要绘制的基类了.

public class InspectorDecoratorEditor : Editor
{public static readonly System.Type EndType = typeof(UnityEngine.MonoBehaviour);     // end type dont need show in inspectorpublic static readonly System.Type BaseEditorType = typeof(UnityEditor.Editor);     // CustomEditor must inherit from it, filterpublic static readonly BindingFlags CustomEditorFieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;    // flag// type cache[Assembly, [scriptType, customEditorType]]protected static Dictionary<Assembly, Dictionary<System.Type, System.Type>> ms_editorReferenceScript= new Dictionary<Assembly, Dictionary<System.Type, System.Type>>();protected List<Editor> m_inheritEditors = null;     // cached editors// ctor, use ctor instead Mono life circle, more user friendly public InspectorDecoratorEditor(){CacheEditorReferenceScript();}#region Main Funcs/// <summary>/// Cache all CustomEditor in current Assembly/// </summary>protected void CacheEditorReferenceScript(){var editorAssembly = Assembly.GetAssembly(this.GetType());      // editor may in diferent assembliesif(ms_editorReferenceScript.ContainsKey(editorAssembly) == false){Dictionary<System.Type, System.Type> cachedData = new Dictionary<System.Type, System.Type>();var types = editorAssembly.GetExportedTypes();foreach(var editorType in types){if(editorType.IsSubclassOf(BaseEditorType)){var scriptType = GetTypeFormCustomEditor(editorType);if(scriptType != null){cachedData[scriptType] = editorType;}}}ms_editorReferenceScript[editorAssembly] = cachedData;}}/// <summary>/// Draw a Target Type Inspector, call OnInspectorGUI/// </summary>/// <typeparam name="T"></typeparam>protected virtual void DrawBaseInspectorGUI<T>() where T : InspectorDecoratorEditor{if(m_inheritEditors == null){m_inheritEditors = new List<Editor>();Dictionary<System.Type, System.Type> scriptEditorCache = null;if(ms_editorReferenceScript.TryGetValue(Assembly.GetAssembly(this.GetType()), out scriptEditorCache) && scriptEditorCache != null){var baseType = target.GetType().BaseType;while(baseType != null && baseType != EndType){System.Type editorType = null;if(scriptEditorCache.TryGetValue(baseType, out editorType) && editorType != null){m_inheritEditors.Add(Editor.CreateEditor(targets, editorType));}baseType = baseType.BaseType;}}}if(m_inheritEditors.Count > 0){for(int i = m_inheritEditors.Count - 1; i >= 0; i--){var drawTarget = m_inheritEditors[i];if(drawTarget && drawTarget.GetType() == typeof(T)){drawTarget.OnInspectorGUI();   // draw target type only, avoid endless loopbreak;}}}}#endregion#region Help Funcspublic static System.Type GetTypeFormCustomEditor(System.Type editorType){var attributes = editorType.GetCustomAttributes(typeof(CustomEditor), false) as CustomEditor[];if(attributes != null && attributes.Length > 0){var attribute = attributes[0];var type = attribute.GetType().GetField("m_InspectedType", CustomEditorFieldFlags).GetValue(attribute) as System.Type;return type;}return null;}#endregion
}

  

  

  修改后的Editor代码如下, 修改的只有继承类以及DrawBaseInspectorGUI<T>函数, 注意这里对于T来说是没有类型检查的, 可是在函数中是有类型匹配的,

就算传入错误类型也是安全的 :

[CustomEditor(typeof(TestBaseClass))]
public class TestBaseClassInspector : InspectorDecoratorEditor
{TestBaseClass _target;private void OnEnable(){_target = target as TestBaseClass;}public override void OnInspectorGUI(){_target.abc = EditorGUILayout.FloatField("基类变量 : ", _target.abc);}
}[CustomEditor(typeof(TestCamera))]
public class TestCameraInspector : InspectorDecoratorEditor
{TestCamera _target = null;private void OnEnable(){_target = target as TestCamera;}public override void OnInspectorGUI(){DrawBaseInspectorGUI<TestBaseClassInspector>();_target.cam = EditorGUILayout.ObjectField("一次继承变量 : ", _target.cam, typeof(Camera), true) as Camera;}
}[CustomEditor(typeof(TestUntiy))]
public class TestUntiyInspector : InspectorDecoratorEditor
{TestUntiy _target = null;private void OnEnable(){_target = target as TestUntiy;}public override void OnInspectorGUI(){DrawBaseInspectorGUI<TestCameraInspector>();_target.hahah = EditorGUILayout.IntField("二次继承变量 : ", _target.hahah);}
}

  然后看看检视面板现在的样子, 完美绘制了基类面板:

DrawBaseInspectorGUI<T>() 这个绘制基类的请求强大的地方就是可以选择从哪个类型开始绘制, 比如
DrawBaseInspectorGUI<TestCameraInspector>();
换成
DrawBaseInspectorGUI<TestBaseClassInspector>();
那么 TestCameraInspector 这个检视面板就被跳过去了 :

  虽然有很多方式能够绘制或者继承子类检视面板, 不过这个应该是个泛用度很高的方案. Over.

转载于:https://www.cnblogs.com/tiancaiwrk/p/10881981.html

Unity检视面板的继承方法研究相关推荐

  1. Unity检视面板重构(OnInspectorGUI重写)

    前言 使用GF框架时,有没有发现很神奇的情况,继承任何模块的辅助器基类脚本(Helper)都会被检视面板自动识别,这里以GF框架为例讲述一下如何做到自动识别脚本的. 1.自动识别脚本 不知道GF框架是 ...

  2. unity Inspector 面板扩展

    通常情况下,我们定义了一个脚本1,公开了一些变量 脚本1: using System.Collections; using System.Collections.Generic; using Unit ...

  3. unity 粒子系统面板参数释义

    **unity 粒子系统面板参数释义** 如何在Unity中实现粒子效果? 首先,右键点击 Hierarchy栏,选择effects->Particle System,这样你就新建了一个粒子系统 ...

  4. 继承ViewGroup研究(汇总) 一、二、三

    转载过来:为一.二.三版本. 仅供参考: 继承ViewGroup研究(1) --简介和一个小Demo 又翻开一个新篇章了,哈哈,上一回学习的是继承View,关于继承View个人感觉不是那么完美,做技术 ...

  5. Unity使用独立配置文件的方法

    在项目中打算使用Unity作为依赖注入容器,于是对Unity做了一些研究,微软给出的文档和实例都是用代码或应用程序配置文件(app.config或web.config)来对Unity做配置的,这样做需 ...

  6. VC启动窗口画面制作方法研究

    VC启动窗口画面制作方法研究 源代码运行效果图如下: 1. 概述 前几天在设计软件时,选择VC作为开发工具,想做个启动画面,由于以前没有制作过,所以到网上搜了一通.网上有几篇相关文章,有两篇我觉得很有 ...

  7. 论文精读-基于双目图像的视差估计方法研究以及实现

    基于双目图像的视差估计方法研究及实现 第一章 绪论 1.1 课题的研究背景与意义 1.2 双目视差估计的研究现状 1.2.1 传统立体匹配方法研究现状 1.2.2 统计学习方法研究现状 1.2.3 深 ...

  8. 基于html5的数据可视化实现方法研究,基于HTML5的数据可视化实现方法研究

    信息科技 Information Technology 基于HTML5的数据可视化实现方法研究 高科同济大学电子与信息学院,上海 201804摘要 HTML5的出现,为数据可视化提供了新的实现方法.本 ...

  9. 液压管路渗漏图像识别检测方法研究

    (一)选题依据 1. 课题研究意义及国内外研究现状 1.1 研究背景及意义 液压系统具有体积小.重量轻.反应灵敏.传递功率大.运动平稳.传动比大.调速方便等特点,广泛运用于各种机械设备中[1].液压系 ...

最新文章

  1. TabLayout-Android M新控件
  2. 查看PLC IP 端口_三种方法实现以太网远程访问西门子PLC!
  3. throw throws 区别
  4. SAP FSM 学习笔记(二) : SAP FSM的微信接入
  5. sql server 更改端口之后的登入方式
  6. 快速排序思路(Hoare版),代码实现
  7. 【Mac】mac移动查找的图片到某个目录
  8. 《Hadoop实战(第2版)》迷你书
  9. 服务器2003系统U盘安装方法,怎么用u盘装2003系统
  10. DenseNet算法详解
  11. 用python做股票因子分析_因子分析(by+alphalens)
  12. 【数学之美】豆瓣9.1 颠覆世界的混沌理论
  13. 计算机软著发明,时健
  14. 高德地图API调用和数据解析
  15. Debian本地源的创建及应用
  16. 计算机网络与技术课本,高等学校计算机科学与技术教材:计算机网络基础教程...
  17. Hadoop学习教程(MapReduce)(四)
  18. ui-app使用pdfh5显示pdf文件 获取pdf总页数和当前阅读页数
  19. 2021年中式面点师(初级)考试题库及中式面点师(初级)操作证考试
  20. spring boot接入微信小程序支付流程

热门文章

  1. DataGrid/DataList在ASP.NET中应用
  2. java发送jsp表格邮件_javaweb收发邮件 servler+jsp实现(一)
  3. java lr分析表建立程序_[源码和文档分享]基于Java实现的LR(1)分析法语法分析程序...
  4. Python-OpenCV学习--USB摄像头读取图像上下翻转
  5. 机器人学习--电子指南针定位导航
  6. 安装 | OpenCV4.2.0 + VS2017安装教程
  7. 北斗导航 | 复杂环境下卫星导航算法(理论)
  8. c语言一串大写字母转小写,C语言的基础函数大小写转换
  9. pylucene构建索引_java-Apache Lucene:建立索引时如何使用TokenSt...
  10. 香帅的北大金融学课笔记10 -- 金融衍生品