赞
踩
早之前写自定义GroupLayout的时候就想要有个Inspector界面属性显隐控制(条件控制)的东西了,当时还完全没有想到该怎么写,最近又遇到了相关的东西就去尝试写了个,经过测试之后能够支持一部分的条件下隐藏某一属性了。
这个我也不知道怎么搞照猫画老虎写了个,先继承PropertyAttribute
然后里面加上自定义的属性,写上构造函数就行了
using System.Collections; using System.Collections.Generic; using UnityEngine; public enum CompareType { NotEqul = 0, Less = 1 << 0, Equl = 1 << 1, Greater = 1 << 2, LessAndEqul = Less | Equl, GreaterAndEqul = Greater | Equl, } public enum CalculateType { None = 0, /// <summary> ///或 /// <summary> Or = 1 << 0, /// <summary> ///与 /// <summary> And = 1 << 1, /// <summary> ///异或 /// <summary> Xor = 1 << 2, /// <summary> /// 取反运算,有点问题,取反是单目运算暂时废弃 /// </summary> Not = 1 << 3, } public class PropertyActiveAttribute : PropertyAttribute { //字段路径 public string FieldPath { get; set; } //说明一下,逻辑是这样的 //获取字段路径所在位置的字段,然后如果需要计算则与计算的值进行一个计算 //然后使用计算得到的值和比较的值进行对应的比较,如果为真那么会隐藏掉 //比较类型 public CompareType Compare { get; set; } //比较的值 public object CompareValue { get; set; } //计算的类型 public CalculateType Calculate { get; set; } = CalculateType.None; //计算的值 public object CalculateValue { get; set; } public PropertyActiveAttribute(string fieldPath, object value, CompareType compare = CompareType.Equl) { FieldPath = fieldPath; CompareValue = value; Compare = compare; } public PropertyActiveAttribute(string fieldPath, CalculateType calculate, object calculateValue, object value, CompareType compare = CompareType.Equl) { FieldPath = fieldPath; Calculate = calculate; CalculateValue = calculateValue; CompareValue = value; Compare = compare; } }
用来拓展编辑器,可以对某一类型或者带有某一特性的字段进行自定义的绘制
该类需要继承PropertyDrawer
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.Linq; using System.Reflection; using System; [CustomPropertyDrawer(typeof(PropertyActiveAttribute), false)] public class PropertyActiveEditor : PropertyDrawer { //字段路径 private string field; //比较的值 private object compareValue; //比较类型 private CompareType compare; //计算的值 private object calculateValue; //计算类型 private CalculateType calculate; //是否隐藏 private bool flag; public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { //attribute是父类的,传过来的是属性值 PropertyActiveAttribute attr = attribute as PropertyActiveAttribute; //对应变量赋值 field = attr.FieldPath; compareValue = attr.CompareValue; compare = attr.Compare; calculate = attr.Calculate; calculateValue = attr.CalculateValue; //获取当前属性所在的类,例如当前属性是a.b,那么就是获取a var parent = property.GetActualObjectParent(); //获取用于条件判断的字段信息,值以及类型 var ComparePropertyField = parent.GetType().GetField(field); var ComparePropertyValue = ComparePropertyField?.GetValue(parent); var ComparePropertyType = ComparePropertyValue?.GetType(); //如果计算的类型不为None说明要计算 object calculateRes = ComparePropertyValue; if (calculate != CalculateType.None) { //目前仅支持int或enum(其实写这个主要为了enum判断) if (CanChangeToInt(ComparePropertyValue) && CanChangeToInt(calculateValue)) { switch (attr.Calculate) { case CalculateType.Or: { calculateRes = (int)ComparePropertyValue | (int)calculateValue; } break; case CalculateType.And: { calculateRes = (int)ComparePropertyValue & (int)calculateValue; } break; case CalculateType.Xor: { calculateRes = (int)ComparePropertyValue ^ (int)calculateValue; } break; default: { return EditorGUI.GetPropertyHeight(property); } } } else { return EditorGUI.GetPropertyHeight(property); } } if (calculateRes == null) return EditorGUI.GetPropertyHeight(property); //等于和不等于直接调用object的Equals if (compare == CompareType.Equl) { flag = calculateRes.Equals(compareValue); } else if (compare == CompareType.NotEqul) { flag = !calculateRes.Equals(compareValue); } else if (ComparePropertyType==compareValue.GetType()&&IsNumberType(ComparePropertyType)) { //其他比较需要使用Comparer来比较两个object switch (compare) { case CompareType.Less: { flag = Comparer.DefaultInvariant.Compare(calculateRes, compareValue) < 0; } break; case CompareType.Greater: { flag = Comparer.DefaultInvariant.Compare(calculateRes, compareValue) > 0; } break; case CompareType.LessAndEqul: { flag = Comparer.DefaultInvariant.Compare(calculateRes, compareValue) <= 0; } break; case CompareType.GreaterAndEqul: { flag = Comparer.DefaultInvariant.Compare(calculateRes, compareValue) >= 0; } break; } } if (flag) return 0; else { return EditorGUI.GetPropertyHeight(property); } } public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { //不隐藏再进行一个绘制 if (!flag) { EditorGUI.PropertyField(position, property, label, true); } } //判断是否是数值类型 public static bool IsNumberType(Type type) { //IsPrimitive就是系统自带的类,IsValueType就是值类型,再排除char剩下的就是int,float这些了 return (type.IsPrimitive && type.IsValueType && type != typeof(char)); } //。。。。 public static bool CanChangeToInt(object value) { try { int i = (int)value; return true; } catch { return false; } } public static bool CanChangeToDouble(object value) { try { double i = (double)value; return true; } catch { return false; } } }
获取属性的父物体
#if UNITY_EDITOR using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; public static class UnityEditorHelper { public static T GetActualObject<T>(this SerializedProperty property) { try { if (property == null) return default(T); var serializedObject = property.serializedObject; if (serializedObject == null) { return default(T); } var targetObject = serializedObject.targetObject; //if (property.depth > 0) //{ var slicedName = property.propertyPath.Split('.').ToList(); List<int> arrayCounts = new List<int>(); for (int index = 0; index < slicedName.Count; index++) { arrayCounts.Add(-1); var currName = slicedName[index]; if (currName.EndsWith("]")) { var arraySlice = currName.Split('[', ']'); if (arraySlice.Length >= 2) { arrayCounts[index - 2] = Convert.ToInt32(arraySlice[1]); slicedName[index] = string.Empty; slicedName[index - 1] = string.Empty; } } } while (string.IsNullOrEmpty(slicedName.Last())) { int i = slicedName.Count - 1; slicedName.RemoveAt(i); arrayCounts.RemoveAt(i); } return DescendHierarchy<T>(targetObject, slicedName, arrayCounts, 0); // } // return default(T); } catch { return default(T); } } public static object GetActualObjectParent(this SerializedProperty property) { try { if (property == null) return default; //获取当前序列化的Object var serializedObject = property.serializedObject; if (serializedObject == null) { return default; } //获取targetObject,这里的targetObject就是 //我不好描述直接举个例子:a.b.c.d.e.f,比如serializedObject就是f,那么targetObject就是a var targetObject = serializedObject.targetObject; //还是上面的例子propertyPath其实就是a.b.c.d.e.f //但是如果其中某一个是Array的话假设是b那么就会变成a.b.Array.data[x].c.d.e.f //其中x为index var slicedName = property.propertyPath.Split('.').ToList(); List<int> arrayCounts = new List<int>(); //根据"."分好后还需要获取其中的数组及其index保存在一个表中 for (int index = 0; index < slicedName.Count; index++) { arrayCounts.Add(-1); var currName = slicedName[index]; if (currName.EndsWith("]")) { var arraySlice = currName.Split('[', ']'); if (arraySlice.Length >= 2) { arrayCounts[index - 2] = Convert.ToInt32(arraySlice[1]); slicedName[index] = string.Empty; slicedName[index - 1] = string.Empty; } } } //清除数组导致的空 while (string.IsNullOrEmpty(slicedName.Last())) { int i = slicedName.Count - 1; slicedName.RemoveAt(i); arrayCounts.RemoveAt(i); } //如果和属性名称相同则清除 if (slicedName.Last().Equals(property.name)) { int i = slicedName.Count - 1; slicedName.RemoveAt(i); arrayCounts.RemoveAt(i); } //如果空了那么返回targetObject为当前的父对象 if (slicedName.Count == 0) return targetObject; //继续清除数组,防止父对象也是数组 while (string.IsNullOrEmpty(slicedName.Last())) { int i = slicedName.Count - 1; slicedName.RemoveAt(i); arrayCounts.RemoveAt(i); } //如果空了那么返回targetObject为当前的父对象 if (slicedName.Count == 0) return targetObject; //获取父物体 return DescendHierarchy<object>(targetObject, slicedName, arrayCounts, 0); } catch { return default; } } //自己看 static T DescendHierarchy<T>(object targetObject, List<string> splitName, List<int> splitCounts, int depth) { if (depth >= splitName.Count) return default(T); var currName = splitName[depth]; if (string.IsNullOrEmpty(currName)) return DescendHierarchy<T>(targetObject, splitName, splitCounts, depth + 1); int arrayIndex = splitCounts[depth]; var newField = targetObject.GetType().GetField(currName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (newField == null) { Type baseType = targetObject.GetType().BaseType; while (baseType != null && newField == null) { newField = baseType.GetField(currName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); baseType = baseType.BaseType; } } var newObj = newField.GetValue(targetObject); if (depth == splitName.Count - 1) { T actualObject = default(T); if (arrayIndex >= 0) { if (newObj.GetType().IsArray && ((System.Array)newObj).Length > arrayIndex) actualObject = (T)((System.Array)newObj).GetValue(arrayIndex); var newObjList = newObj as IList; if (newObjList != null && newObjList.Count > arrayIndex) { actualObject = (T)newObjList[arrayIndex]; } } else { actualObject = (T)newObj; } return actualObject; } else if (arrayIndex >= 0) { if (newObj is IList) { IList list = (IList)newObj; newObj = list[arrayIndex]; } else if (newObj is System.Array) { System.Array a = (System.Array)newObj; newObj = a.GetValue(arrayIndex); } } return DescendHierarchy<T>(newObj, splitName, splitCounts, depth + 1); } } #endif
[Flags] public enum TestEnum { a=1, b=1<<1, c = 1<<2, d = 1<<3 } public class Test : MonoBehaviour { public float speed = 5.0f; //当小于10.0f时就不会显示,超过时会显示超速 [PropertyActive("speed", 10.0f, CompareType.Less)] public string OverSpeed = "超速了"; public TestEnum enumtest = TestEnum.c; //当enumtest中没有a时就隐藏了 [PropertyActive("enumtest", CalculateType.And, TestEnum.a, 0, CompareType.Equl)] public string NotDouble = "测试计算"; }
CSDN上的都要积分烦死了,还是自己写爽。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。