本文固定链接: http://www.xuanyusong.com/archives/4213
转载请注明: 雨松MOMO 2016年07月13日 于 雨松MOMO程序研究院 发表
虽然mono是支持unicode的。可以在枚举里写中文,但是我还是觉得写英文好一些。可是在编辑器上策划是希望看到的是中文的,还有就是枚举的展示排序功能,策划在编辑的时候为了方便希望把常用的枚举排上前面。
把如下代码放到你的工程里就可以直接用了。
using UnityEngine;
using System;
#if UNITY_EDITOR
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#endif
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)]
public class EnumLabelAttribute : PropertyAttribute
{
public string label;
public int[] order = new int[0] ;
public EnumLabelAttribute(string label)
{
this.label = label;
}
public EnumLabelAttribute(string label,params int[] order)
{
this.label = label;
this.order = order;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(EnumLabelAttribute))]
public class EnumLabelDrawer : PropertyDrawer
{
private Dictionary<string, string> customEnumNames = new Dictionary<string, string>();
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
SetUpCustomEnumNames(property, property.enumNames);
if (property.propertyType == SerializedPropertyType.Enum)
{
EditorGUI.BeginChangeCheck();
string[] displayedOptions = property.enumNames
.Where(enumName => customEnumNames.ContainsKey(enumName))
.Select<string, string>(enumName => customEnumNames[enumName])
.ToArray();
int[] indexArray = GetIndexArray (enumLabelAttribute.order);
if(indexArray.Length != displayedOptions.Length)
{
indexArray = new int[displayedOptions.Length];
for(int i =0; i< indexArray.Length; i++){
indexArray[i] = i;
}
}
string[] items = new string[displayedOptions.Length];
items[0] = displayedOptions[0];
for (int i=0; i<displayedOptions.Length; i++) {
items[i] = displayedOptions[indexArray[i]];
}
int index = -1;
for (int i=0; i<indexArray.Length; i++) {
if (indexArray[i] == property.enumValueIndex) {
index = i;
break;
}
}
if ( (index == -1) && (property.enumValueIndex != -1) ) { SortingError (position,property,label); return; }
index = EditorGUI.Popup(position, enumLabelAttribute.label,index, items);
if (EditorGUI.EndChangeCheck())
{
if (index >= 0)
property.enumValueIndex = indexArray[index];
}
}
}
private EnumLabelAttribute enumLabelAttribute
{
get
{
return (EnumLabelAttribute)attribute;
}
}
public void SetUpCustomEnumNames(SerializedProperty property, string[] enumNames)
{
object[] customAttributes = fieldInfo.GetCustomAttributes(typeof(EnumLabelAttribute), false);
foreach (EnumLabelAttribute customAttribute in customAttributes)
{
Type enumType = fieldInfo.FieldType;
foreach (string enumName in enumNames)
{
FieldInfo field = enumType.GetField(enumName);
if (field == null) continue;
EnumLabelAttribute[] attrs = (EnumLabelAttribute[])field.GetCustomAttributes(customAttribute.GetType(), false);
if (!customEnumNames.ContainsKey(enumName))
{
foreach (EnumLabelAttribute labelAttribute in attrs)
{
customEnumNames.Add(enumName, labelAttribute.label);
}
}
}
}
}
int[] GetIndexArray (int[] order)
{
int[] indexArray = new int[order.Length];
for (int i = 0; i < order.Length; i++) {
int index = 0;
for (int j = 0; j < order.Length; j++) {
if (order[i] > order[j]) {
index++;
}
}
indexArray[i] = index;
}
return (indexArray);
}
void SortingError (Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, new GUIContent(label.text + " (sorting error)"));
EditorGUI.EndProperty();
}
}
public class EnumLabel
{
static public object GetEnum(Type type, SerializedObject serializedObject, string path)
{
SerializedProperty property = GetPropety(serializedObject,path);
return System.Enum.GetValues(type).GetValue(property.enumValueIndex);
}
static public object DrawEnum(Type type, SerializedObject serializedObject, string path)
{
return DrawEnum(type,serializedObject, GetPropety(serializedObject,path));
}
static public object DrawEnum(Type type, SerializedObject serializedObject,SerializedProperty property)
{
serializedObject.Update();
EditorGUILayout.PropertyField(property);
serializedObject.ApplyModifiedProperties();
return System.Enum.GetValues(type).GetValue(property.enumValueIndex);
}
static public SerializedProperty GetPropety(SerializedObject serializedObject, string path)
{
string []contents = path.Split('/');
SerializedProperty property = serializedObject.FindProperty(contents[0]);
for(int i=1; i< contents.Length; i++){
property = property.FindPropertyRelative(contents[i]);
}
return property;
}
}
#endif
使用是这样的,第二个参数就是排序。接收int的不固定参数。
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour
{
[EnumLabel("我是的类型",10,1,5,2)]
public NewType newType = NewType.One;
}
public enum NewType : byte
{
[EnumLabel("我是1")]
One = 10,
[EnumLabel("我是2")]
Two = 1,
[EnumLabel("我是3")]
Three = 5,
[EnumLabel("我是4")]
Four = 2
}
OK 中文与排序都OK了。
但是,有时候我们做编辑器的时候是自己调用OnInspectorGUI来绘制面板的。而且我的枚举对象可能会在另外一个子对象里,或者在子对象里的一个List里面的子对象里。
比如这样, class.data.newType 就是这个类对象的结构,你可以按照你自己类的结构去拼这个字符串。
public override void OnInspectorGU()
{
NewType oldType = (NewType)EnumLabel.GetEnum(typeof(NewType),serializedObject,"class/data/newType");
NewType newType = (NewType)EnumLabel.DrawEnum(typeof(NewType),serializedObject,"class/data/newType");
if(oldType != newType)
{
//类型发生改变
}
}
还有一种特殊的就是可能枚举在list里,这样在绘制的时候是需要遍历的。
public override void OnInspectorGU()
{
SerializedProperty property = EnumLabel.GetPropety(serializedObject,"class/datas");
for(int i =0; i< count; i++)
{
SerializedProperty eProperty = property.GetArrayElementAtIndex(i);
NewType newType = (NewType)EnumLabel.DrawEnum(typeof(NewType),serializedObject
,eProperty.FindPropertyRelative("newType"));
}
}
OK大功告成。
参考文章:
https://github.com/anchan828/property-drawer-collection/blob/master/EnumLabel/EnumLabelAttribute.cs
http://forum.unity3d.com/threads/enum-inspector-sorting-attribute.357558/
转by:蒋志杰