Odin界面编辑器
记录 2312
一、Odin Inspector介绍
Odin Inspector(Version:3.1.6) 是 Unity 的一个插件,是一款可自定义的、功能强大的界面编辑器。可以使用插件自身提供的100多个插件轻松的编辑出美观的界面,让开发者更容易使用。
二、特性
1.Unity与Odin类似特性的对比
Unity也有一些特性,但涉及界面开发的并不多。而Odin作为界面编辑器,它提供了100多个特性,不过基本上都是作用与字段上的特性,同时有很多和Unity特性类似的,就界面开发来说非常的全面。
以下举例几个类似的特性对比:
1、InspectorNameAttribute 和 LabelText,字段别名显示
//Unity Attribute , 作用与枚举值,可以给枚举值起个别名
public enum unityEnum{
[inspcetorName("a的别名")]
a,
[inspcetorName("b的别名")]
b,
}
//Odin Attribute ,给字段和枚举值个名字
public enum odinEnum{
[LabelText("a的别名")]
a,
//注意这里Odin使用$意思是使用字段D的值,但是在枚举里是不起作用的,实际上显"$D"
[LabelText("$D")]
b,
}
//在Odin特性里,使用@代表引用一个方法
[LabelText("@dataTime.Now.Tostring(\"HH:mm:ss\")")]
public string D = "name:D";
2、SpaceAttribute和 PropertySpace 填充
//Unity Space
[Space(10)] //只能用于字段,用于当前字段和下一字段的空白填充
public int unitySpace;
//Odin PropertySpace
[PropertySpace(spaceBefore:10,spaceAfter:10)]//可用于字段,可以对字段前后都进行填充,更灵活
public int odinSpace;
[PropertySpace(spaceBefore:40,spaceAfter:100)]//也可用于属性,可以对字段前后都进行填充,更灵活
public int property { get; set; }
3、PropertyRange
///Unity Range
[Range(0, 10)] //只能用于字段
public int unityRange = 1;
//Odin PropertyRange
[PropertyRange(0,10)] //可用于属性
public int odinProperRange { get; set; }
[PropertyRange("unityRange", 10)] //也可以应用其他变量作为最大最小值,不在范围内时会有错误提示
public int odinRange = 2;
4、Title 和Header 标题提示显示
//Unity Header
[Header("UnityHeader")] //仅可用于字段
public string myTitle;
//Odin Title
//第一个参数为一级标题;第二个参数为二级标题;第三个参数为位置,默认靠左;第四个参数为是否加下划线,默认为true;第五个参数为是否加粗一级标题,默认为True
[Title("myTitle", "Subtitle", titleAlignment:TitleAlignments.Centered,horizontalLine:true,bold:true)]
public string OdinTitle1;
//同时方法也是可以添加标题,仅限于添加按钮特性的方法
[Title("$myTitle")][Button]
public void OdinTitleFunc(){}
2、几个好用的Odin特性
1、DictionaryDrawerSettings 字典使用
//DictionaryDrawerSettings
//DictionaryDrawerSettings 有4个定义参数,KeyLabel为Key的字段文本,ValueLabel为value的字段文本
//displayMode定义字典的展开方式,KeyColumnWidth为显示的Key的宽度
//一般来说非可序列话的元素是无法在面板展示的,如果想要在Inspector中显示字典的格式,需要添加[ShowInInspector]或者让类继承SerializedBehaviour,
[ShowInInspector]
[DictionaryDrawerSettings(KeyLabel = "Key",ValueLabel = "value",DisplayMode = DictionaryDisplayOptions.OneLine,KeyColumnWidth = 100)]
public Dictionary<string, string> odinDic;
2、[BoxGroup]、[HorizontalGroup]和[HideIfGroup] 窗口布局
//有相同标题的字段会放到一个“盒子”里,且盒子的名字为SomeTitle,同时ShowLabel可以控制标题是否显示
[BoxGroup("SomeTitle",ShowLabel = false)]
public int a;
[BoxGroup("SomeTitle")]
public int b;
//在父级标题下加子标题,形成嵌套,就是个文件夹路径
[BoxGroup("SomeTitle/SubTitle")]
public int a1;
//[HorizontalGroup] 可以把当前子标题“box“下的所有Group水平排列,
[HorizontalGroup("box",LabelWidth = 50)]
[BoxGroup("box/left")]
public int left;
//同时HorizontalGroup也可以进行嵌套,然后在”box/right"下的所有子Group又会是水平排列
[HorizontalGroup("box/right",LabelWidth = 50)]
[BoxGroup("box/right/A")]
public int right;
//Hide if Group,就是根据传递的值来看是否隐藏或显示当前组,
public bool toggle = true;
[HideIfGroup("toggle")][VerticalGroup]
public int testHideifgroup;
3、FilePath和FolderPath 筛选文件路径
//FilePath,打开文件路径,并把路径赋值给对应变量,支持打开文件夹自选,也支持拖拽过来
//ParentFolder可以规定打开时的初始文件夹路径,Extensions筛选扩展名的。AbsolutePath 是否需要绝对路径,RequireExistingPath 所选路径是否存在,
[FilePath(ParentFolder = "Assets/Plugins",Extensions = "cs",AbsolutePath = true, RequireExistingPath = true)]
public string filePath;
//FolderPath 是打开文件夹,输入的也是文件加路径,也只能输入文件夹路径,
[FolderPath(ParentFolder = "Assets/Plugins",AbsolutePath = true, RequireExistingPath = true)]
public string folderPath;
4、Validition 检测输入
//ValidatorInput 用于检测输入,condition 用于自定义检测函数,defaultmessage 默认提示消息,MessageType 提示消息类型
[ValidateInput("CheckName","defaultMessage",MessageType = InfoMessageType.Info)]
public GameObject go;
private bool CheckName(GameObject go, ref string errorMessage,ref InfoMessageType ? infoMessageType)
{
if (go == null)
{
infoMessageType = InfoMessageType.Error;
errorMessage = "没对象";
return false;
}
string name = go.gameObject.name;
if (name == "")
{
infoMessageType = InfoMessageType.Warning;
errorMessage = "给个名字呗";
return false;
}
return true;
}
三、自定义特性
1、OdinValueDrawer 自定义值特性
可以自定一值特性,模板如下,可以使用泛型,这里继承SerializedMonoBehaviour 并加上OdinSerialize标签是为了把对应值序列化,然后显示在面板上。
public class Test : SerializedMonoBehaviour
{
[OdinSerialize]
public TestValue<int,int> tt = new TestValue<int,int>();
}
public class TestValue<T1,T2>
{
public T1 t1;
public T2 t2;
}
public class TestValueDrawer : OdinValueDrawer<TestValue<int, int>>
{
protected override void DrawPropertyLayout(GUIContent label){ }
}
public class TestValueDrawer<T1,T2> : OdinValueDrawer<TestValue<T1, T2>>
{
protected override void DrawPropertyLayout(GUIContent label){ }
}
2、OdinAttributeDrawer 自定义特性绘制
绘制自定义特性,和普通特性使用方式一样
public class AttributeTest : MonoBehaviour
{
[TestDraw(1)] public int a;
}
//定义特性运用的范围
[AttributeUsage(AttributeTargets.Field)]
public class TestDrawAttribute : Attribute
{
public int value;
public TestDrawAttribute(int value)
{
this.value = value;
}
}
public class TestDrawAttributeDraw : OdinValueDrawer<TestDrawAttribute>
{
protected override void DrawPropertyLayout(GUIContent label){ }
}
3、OdinGroupDrawer 自定义组特性
public class GroupTest : MonoBehaviour
{
[GroupDrap(1)] public int a;
}
[AttributeUsage(AttributeTargets.All)]
public class GroupDrap : PropertyGroupAttribute
{
public int value;
public GroupDrap(int value,int order = 0):base("_DefaultGroup",order)
{
this.value = value;
}
}
public class GroupDrapDraw : OdinGroupDrawer<GroupDrap>
{
protected override void DrawPropertyLayout(GUIContent label){ }
}
4、AttributeValidator 自定义验证器特性
可以写一些验证器相关的
public class ValidationExample : MonoBehaviour
{
[NotOne] public int NotOne;
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class NotOneAttribute : Attribute
{
}
public class NotOneAttributeValidator : AttributeValidator<NotOneAttribute, int>
{
protected override void Validate(ValidationResult result)
{
if (this.ValueEntry.SmartValue == 1)
{
result.Message = "1 is not a valid value.";
result.ResultType = ValidationResultType.Error;
}
}
}
四、EditorWindow
Odin提供了两个类,OdinEditorWindow和OdinMenuEditorWindow,他们分别用来编辑通用窗口和菜单窗口,使用这俩类编写窗口时UI不必写在OnGui里了,不在需要调用EditorLayout 、Layout、OnGui等这些Unity原生接口,可以直接使用Odin丰富的特性编写,这样写不仅更简单且更容易维护。
1、OdinEditorWindow:
基础窗口,类似原生EditorWindow
//基础窗口可以继承OdinEditorWindow,创建窗口是直接调用GetWidow就够了
public class windowTest : OdinEditorWindow
{
[MenuItem("WindowTest/OdinBaseWindow")]
private static void OpenWindow()
{
var window = GetWindow<windowTest>();
window.position = new Rect(0, 0, 1980, 1080);
}
//不用写在 OnGui 里了 ,可直接运用特性写入
[LabelText("测试文字")]
public string test;
}
2、OdinMenuEditorWindow
菜单树窗口,就是提供了一个类似Unity Project Settings的窗口,当然显示是更加丰富。
//继承OdinMenuEditorWindow,创建窗口是直接调用GetWidow就够了
public class windowTest : OdinMenuEditorWindow
{
[MenuItem("WindowTest/OdinMenuEditorWindow")]
private static void OpenWindow()
{
var window = GetWindow<windowTest>();
window.position = new Rect(0, 0, 1980, 1080);
}
[BoxGroup("当前页面内容")]
public string test;
protected override OdinMenuTree BuildMenuTree()
{
OdinMenuTree tree = new OdinMenuTree(supportsMultiSelect: false) //为true时,可以按着ctrl多选
{
//path 菜单树的名,文件夹形式的,可以嵌套, instance 需要显示在当前菜单下显示的页面,EditorIcon 图标
{"Home", this , EditorIcons.House},
{"OdinSetting", null , EditorIcons.SettingsCog},
{"OdinSetting/Color paletter", ColorPaletteManager.Instance , EditorIcons.EyeDropper}
};
var customMenuStyle = new OdinMenuStyle
{
BorderPadding = 0f,
AlignTriangleLeft = true,
TriangleSize = 16f,
TrianglePadding = 0f,
Offset = 20f,
Height = 23,
IconPadding = 0f,
BorderAlpha = 0.323f
};
//定义菜单树样式
tree.DefaultMenuStyle = customMenuStyle;
//是否显示搜索栏
tree.Config.DrawSearchToolbar = true;
//自定义搜索方式,也可以不定义
tree.Config.SearchFunction = (obj) => !obj.Name.StartsWith("Odin");
//也能这样定义,但是发现没啥用
/*this.DrawMenuSearchBar = true;
this.CustomSearchFunction = (obj) => !obj.Name.StartsWith("Odin");*/
//AddAllAssetsAtPath 把assetFolderPath下的所有对应类型的文件插入到menuPath下
tree.AddAllAssetsAtPath("Odin Settings/More Odin Settings", "Plugins/Sirenix", typeof(ScriptableObject), true);
//AddassetAtPath 把支援assetPath插入到menuPath下
tree.AddAssetAtPath("Odin Getting Started", "Plugins/Sirenix/Getting Started With Odin.asset");
//MenuItems.Insert 在Index位置插入一个 OdinMenuItem,这个是在最外层插入
tree.MenuItems.Insert(2, new OdinMenuItem(tree, "Menu Style", tree.DefaultMenuStyle));
//Add添加一个菜单
tree.Add("Menu/Items/Are/Created/As/Needed", new GUIContent());
//默认排序 排序方式是,有子菜单的在上面,然后同级按照首字母排序
tree.SortMenuItemsByName();
//自定义排序
tree.EnumerateTree(true).SortMenuItemsByName((obj1,obj2) => 0);
return tree;
}
}
总结
Odin特性大概有100多个,目前只举例了一点,更多的还是需要看官网,或者下载插件,点击 Tools->Odin->Inspector->Attribute Overview.
Odin提供的众多特性可以让我们非常快速的编写代码,搭建美观且强大的界面,它也允许我们轻松的扩展和定制我们的编辑器,通过编写自定义属性绘制器、值绘制器等,我们可以快速编写我们想要的功能。
嗯·推荐使用