简介
基于 IMGUI 的编辑器 UI 框架,目的是简化编辑器开发时的 UI 构建。利用特性标签进行 UI 的初始化。
对于变量,我们只需要打上对应的标签,就能够在 UI 面板上显示对应的 UI。
对于方法,我们只需要打上 Button 标签,就能够生成一个实现该方法的按钮。
同时,本框架还支持对 UI 的样式和布局进行有限的修改,同样也是通过特性实现。
UI 界面的渲染顺序按照编辑器脚本对象的声明顺序排序,布局的结构也要按照顺序声明,可以看作是以代码的形式绘制 UI。
本框架支持自定义拓展功能,具体的使用说明和拓展规则见:
原理
初始化特性
我们通过基类初始化获取 Type,然后通过 Type 获取 members 并且按照声明顺序排序,之后通过遍历,在其循环体内根据对应的特性类别进行 UI 的渲染函数初始化。
为了防止频繁反射,因此所有的 UI 都在编辑器展示的时候构造,数据的获取和存储都从反射转为委托。又因为 IMGUI 构造 UI 的方法无法在 OnGUI
以外的地方使用,因此我们在初始化时得到的是构造对应 UI 的方法函数。
特性声明
我们在定义特性的时候需要传入一个 [CallerLineNumber] int
类型的变量,该变量用于获取调用特性构造函数的行号,其中 [CallerLineNumber]
也是一个特性,用于获取调用方代码的行号。
只有通过这个方法才能自动获取到正确的声明顺序。如果你不想用这个方法,也可以在特性显示声明一个表明顺序的变量,然后手动传参,并且修改编辑器初始化函数中的排序方法。
渲染
渲染函数初始化
UI 渲染结构
为了支持布局的修改,我们就要规划好整个渲染的结构和顺序。
布局作为最外层的框架,需要把属于该布局的 UI 包裹在其中,并且可能存在布局套布局的情况。因此我们使用树结构来存储布局以及对应的 UI。
我们把 UI 的渲染函数或布局的节点存储在同一个 object
列表中,以便在渲染时按照正确的顺序渲染。
同时,我们设置一个函数委托,用于在渲染布局的时候先把外层的布局 UI 渲染好,然后我们再渲染内部的具体 UI。
UI 渲染具体过程
为了能够在 OnGUI 之外的地方使用 GUI 相关的方法,我们需要把具体的渲染行为封装为函数,之后在 OnGUI 中执行。
本框架把函数渲染分为三个部分:
- UI 渲染。
- Style 渲染。
- GUILayout 渲染。
UI 渲染负责生成 UI 对象,Style 渲染负责生成 GUIStyle 对象,而 GUILayout 渲染负责生成 GUILayout 数组。
最后在组合 UI 的时候把 GUIStyle 和 GUILayout 数组传入 UI 渲染函数。
例:
1 | Action<GUIStyle, GUILayoutOption[]> label = (GUIStyle style, GUILayoutOption[] options) => |
在上面的函数中,UI 渲染函数就是这个 Action 委托,Style 渲染函数在 OnGUI 执行传入 GUIStyle style
,GUILayout 渲染函数在 OnGUI 执行传入 GUILayoutOption[] options
。最后我们执行完 UI 渲染函数就能够得到对应的 UI。
布局渲染函数的初始化需要传入具体的渲染方法,默认有两种,一种 NormalRender
;另一种是 FlexRender
。这两种都在 BaseEditor
中定义。一般情况下只需要用到第一种,第二种是流式布局专用的。如果有其他需要也可以自己新增渲染函数。
具体的生成过程请参考项目工程和项目文档。
渲染函数执行
渲染函数在 OnGUI 中执行,分为两种情况:
- 当前对象为布局节点,则执行节点内的
_layout
函数。 - 当前对象为 UI,则执行
NormalRender
。
1 | private void Render(LayoutNode node) |
以 NormalRender
来说,遍历对象 List,如果是布局节点,则递归调用 Render
方法渲染;如果是 UI,则执行对应的渲染委托函数。
1 | /// <summary> |
项目
由于本项目代码较多,因此请移步 GitHub 查看详细代码。
更新日志
- 修改部分说明。
- 更新基础内容。