之前遇到过一个需求是要在下拉框的目录做一个标记来指示状态,应该很自然就可以想到能不能修改一下 icon,比如把文件夹的那个icon改成其他颜色的,这样会比修改显示名字毫无疑问更加显眼。
不过其实想要进行更大限度的修改是完全可以的,只需要魔改一下 ValueDropdown 就行。
先说一下简单的解决先前提到的需求的办法吧——改显示名字。
一般是使用 ValueDropdownList<T>
或者 IEnumerable<ValueDropdownItem<T>>
(二者是等价的) 作为函数的返回值,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 [ShowInInspector, LabelText("测试下拉框" ) ] [ValueDropdown(nameof(GetAllowIndexs)) ] private int Index;private ValueDropdownList<int > GetAllowIndexs (){ var list = new ValueDropdownList<int >(); for (int i = 0 ; i < 10 ; i++) { list.Add($"The {i + 1 } item" , i); } return list; }
效果如下,可以给每个 value 都指定自定义的名字,不过更复杂的操作似乎就不行了(或者我没有找到?)
拓展 ValueDropdown 既然原本的 ValueDropdown 无法满足需求,那就自己搓一个吧,写一个类继承原来的 ValueDropdown 特性。
然后我们再原来的基础上,再添加一个回调字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #if UNITY_EDITOR && ODIN_INSPECTOR using System;using System.Diagnostics;namespace Sirenix.OdinInspector ;[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true) ] [Conditional("UNITY_EDITOR" ) ] public class CustomValueDropdownAttribute : ValueDropdownAttribute { public string ItemAction; public CustomValueDropdownAttribute (string valueGetter, string itemAction ) : base (valueGetter ) { ItemAction = itemAction; } } #endif
然后自定义 attribute drawer
1 2 3 4 5 6 namespace Sirenix.OdinInspector.Editor.Drawers ;public sealed class CustomValueDropdownAttributeDrawer : OdinAttributeDrawer <CustomValueDropdownAttribute >{ }
简单看一下 ValueDropdownAttributeDrawer
的实现,就会发现是基于 OdinMenuTree 做的,每一项其实都是一个 OdinMenuItem,所以不妨让我们的自定义的回调的参数是 OdinMenuItem,这样就可以实现更大限度的自定义每一项。
添加一个 ActionResolver 字段原来解析传入的方法名
1 private ActionResolver? itemAction;
然后在初始化函数中添加解析逻辑,(也别忘了设置错误信息)
1 2 3 4 5 6 7 8 9 10 if (base .Attribute.ItemAction is not null ){ itemAction = ActionResolver.Get( base .Property, base .Attribute.ItemAction, new [] { new ActionResolvers.NamedValue("item" , typeof (OdinMenuItem)) } ); } error = rawGetter.ErrorMessage ?? itemAction?.ErrorMessage;
翻一下逻辑,会发现设置 icon 是通过 AddThumbnailIcons(preferAssetPreviewAsIcon: true);
调用。所以我们修改一下这部分的逻辑,当 itemAction 为空时,就继续走老逻辑,如果不为空,那就尝试调用解析的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 else { genericSelector.SelectionTree.EnumerateTree(x => { itemAction?.Context.NamedValues.Set("item" , x); itemAction?.DoAction(); if (x.Icon == null ) { x.AddThumbnailIcon(preferAssetPreviewAsIcon: true ); } }); }
测试效果 在原来的测试代码那里添加一个函数
1 2 3 4 private void HandleItem (OdinMenuItem item ){ item.Icon = EditorIcons.Flag.Active; }
并且修改字段的特性
1 [CustomValueDropdown(nameof(GetAllowIndexs), nameof(HandleItem)) ]