当前位置:   article > 正文

【Unity3D】Inspector界面属性显隐控制(条件控制)_unity 自定义 inspector 让某个字段不显示

unity 自定义 inspector 让某个字段不显示

前言(可以不看)

早之前写自定义GroupLayout的时候就想要有个Inspector界面属性显隐控制(条件控制)的东西了,当时还完全没有想到该怎么写,最近又遇到了相关的东西就去尝试写了个,经过测试之后能够支持一部分的条件下隐藏某一属性了。

实现

1.自定义Attribute

这个我也不知道怎么搞照猫画老虎写了个,先继承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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

2. UnityEditor的CustomPropertyDrawer特性

用来拓展编辑器,可以对某一类型或者带有某一特性的字段进行自定义的绘制
该类需要继承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;
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159

3.额外代码

获取属性的父物体

#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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200

4. 使用

[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 = "测试计算";
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

没超速没选a
超速了选了a

结语

CSDN上的都要积分烦死了,还是自己写爽。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/106472?site
推荐阅读
相关标签
  

闽ICP备14008679号