【转】在Unity中创建可用Inspector预编辑的Dictionary类型(转载/狗屁不通机翻)

懂的就直接看原贴吧~

https://forum.unity.com/threads/finally-a-serializable-dictionary-for-unity-extracted-from-system-collections-generic.335797/

总的来说你需要创建一个字典模板类,实现ISerializationCallbackReceiver接口使它支持序列化:

public class SerializableDictionary<TK, TV> : ISerializationCallbackReceiver
{
    private Dictionary<TK, TV> _Dictionary;
    [SerializeField] List<TK> _Keys;
    [SerializeField] List<TV> _Values;
 
    // wrapper methods, serialization, etc...
}

为了实际的使用,不得不创建一个新的类,继承这个模板类

[Serializable]
public class MyDictionary : SerializableDictionary<string, int> { }

你还得为这个新类注册一个绘制器,定义它在Inspector中表现行为

[CustomPropertyDrawer(typeof(MyDictionary))]
public class MyDictionaryDrawer : DictionaryDrawer<string, int> { }

 

机翻:

大家好,Unity不知道如何序列化通用词典。从4.6开始,我们获得了ISerializationCallbackReceiver,它使我们能够使用自定义序列化来序列化Unity无法实现的类型。然而; 当使用此接口序列化字典时,这是不知道的。例如,如果您继承Dictionary <TK,TV>并添加序列化的键/值列表,则会遇到一些非常奇怪的问题(很可能与线程相关),如此此处所示。另一种方法是使用合成代替继承,并使字典对象与序列化的键/值列表一起位于序列化的字典类中,即:

public class SerializableDictionary<TK, TV> : ISerializationCallbackReceiver
{
    private Dictionary<TK, TV> _Dictionary;
    [SerializeField] List<TK> _Keys;
    [SerializeField] List<TV> _Values;
 
    // wrapper methods, serialization, etc...
}

替换掉:

public class SerializableDictionary<TK, TV> : Dictionary<TK, TV>, ISerializationCallbackReceiver
{
    [SerializeField] List<TK> _Keys;
    [SerializeField] List<TV> _Values;
 
    // serialization, etc...
}

但这对我来说还是多余的,我们不得不编写包装器并添加两个列表以进行序列化……

如果Dictionary类本身可以被Unity序列化,那会很好吗?

嗯,这就是我基本上通过提取Dictionary <TK,TV>代码并用[SerializeField]标记必要字段来完成的工作-并对其进行了稍微的重构/清理(重命名了这些字段,删除了非通用接口的实现,并进行了分解而不是'Entry'类中的'hashCode','next','key'和'value'改为数组)

我留下一点评论的是“ IsWellKnownEqualityComparer”,因为我不确定它-我做了一些测试,它似乎没有任何影响。如果你知道一个事实,那就是 非常重要,请通知我。

当然,您仍然必须继承子类,即:

[Serializable]
public class MyDictionary : SerializableDictionary<string, int> { }
 
public class Test : MonoBehaviour
{
    public MyDictionary dictionary;
}

我还添加了一个索引器,该索引器接受默认值,如果找不到该键,则返回该值。还有一个主要用于调试原因的AsDictionary属性。
 

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
 
[Serializable, DebuggerDisplay("Count = {Count}")]
public class SerializableDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    [SerializeField, HideInInspector] int[] _Buckets;
    [SerializeField, HideInInspector] int[] _HashCodes;
    [SerializeField, HideInInspector] int[] _Next;
    [SerializeField, HideInInspector] int _Count;
    [SerializeField, HideInInspector] int _Version;
    [SerializeField, HideInInspector] int _FreeList;
    [SerializeField, HideInInspector] int _FreeCount;
    [SerializeField, HideInInspector] TKey[] _Keys;
    [SerializeField, HideInInspector] TValue[] _Values;
 
    readonly IEqualityComparer<TKey> _Comparer;
 
    // Mainly for debugging purposes - to get the key-value pairs display
    public Dictionary<TKey, TValue> AsDictionary
    {
        get { return new Dictionary<TKey, TValue>(this); }
    }
 
    public int Count
    {
        get { return _Count - _FreeCount; }
    }
 
    public TValue this[TKey key, TValue defaultValue]
    {
        get
        {
            int index = FindIndex(key);
            if (index >= 0)
                return _Values[index];
            return defaultValue;
        }
    }
 
    public TValue this[TKey key]
    {
        get
        {
            int index = FindIndex(key);
            if (index >= 0)
                return _Values[index];
            throw new KeyNotFoundException(key.ToString());
        }
 
        set { Insert(key, value, false); }
    }
 
    public SerializableDictionary()
        : this(0, null)
    {
    }
 
    public SerializableDictionary(int capacity)
        : this(capacity, null)
    {
    }
 
    public SerializableDictionary(IEqualityComparer<TKey> comparer)
        : this(0, comparer)
    {
    }
 
    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
    {
        if (capacity < 0)
            throw new ArgumentOutOfRangeException("capacity");
 
        Initialize(capacity);
 
        _Comparer = (comparer ?? EqualityComparer<TKey>.Default);
    }
 
    public SerializableDictionary(IDictionary<TKey, TValue> dictionary)
        : this(dictionary, null)
    {
    }
 
    public SerializableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
        : this((dictionary != null) ? dictionary.Count : 0, comparer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");
 
        foreach (KeyValuePair<TKey, TValue> current in dictionary)
            Add(current.Key, current.Value);
    }
 
    public bool ContainsValue(TValue value)
    {
        if (value == null)
        {
            for (int i = 0; i < _Count; i++)
            {
                if (_HashCodes[i] >= 0 && _Values[i] == null)
                    return true;
            }
        }
        else
        {
            var defaultComparer = EqualityComparer<TValue>.Default;
            for (int i = 0; i < _Count; i++)
            {
                if (_HashCodes[i] >= 0 && defaultComparer.Equals(_Values[i], value))
                    return true;
            }
        }
        return false;
    }
 
    public bool ContainsKey(TKey key)
    {
        return FindIndex(key) >= 0;
    }
 
    public void Clear()
    {
        if (_Count <= 0)
            return;
 
        for (int i = 0; i < _Buckets.Length; i++)
            _Buckets[i] = -1;
 
        Array.Clear(_Keys, 0, _Count);
        Array.Clear(_Values, 0, _Count);
        Array.Clear(_HashCodes, 0, _Count);
        Array.Clear(_Next, 0, _Count);
 
        _FreeList = -1;
        _Count = 0;
        _FreeCount = 0;
        _Version++;
    }
 
    public void Add(TKey key, TValue value)
    {
        Insert(key, value, true);
    }
 
    private void Resize(int newSize, bool forceNewHashCodes)
    {
        int[] bucketsCopy = new int[newSize];
        for (int i = 0; i < bucketsCopy.Length; i++)
            bucketsCopy[i] = -1;
 
        var keysCopy = new TKey[newSize];
        var valuesCopy = new TValue[newSize];
        var hashCodesCopy = new int[newSize];
        var nextCopy = new int[newSize];
 
        Array.Copy(_Values, 0, valuesCopy, 0, _Count);
        Array.Copy(_Keys, 0, keysCopy, 0, _Count);
        Array.Copy(_HashCodes, 0, hashCodesCopy, 0, _Count);
        Array.Copy(_Next, 0, nextCopy, 0, _Count);
 
        if (forceNewHashCodes)
        {
            for (int i = 0; i < _Count; i++)
            {
                if (hashCodesCopy[i] != -1)
                    hashCodesCopy[i] = (_Comparer.GetHashCode(keysCopy[i]) & 2147483647);
            }
        }
 
        for (int i = 0; i < _Count; i++)
        {
            int index = hashCodesCopy[i] % newSize;
            nextCopy[i] = bucketsCopy[index];
            bucketsCopy[index] = i;
        }
 
        _Buckets = bucketsCopy;
        _Keys = keysCopy;
        _Values = valuesCopy;
        _HashCodes = hashCodesCopy;
        _Next = nextCopy;
    }
 
    private void Resize()
    {
        Resize(PrimeHelper.ExpandPrime(_Count), false);
    }
 
    public bool Remove(TKey key)
    {
        if (key == null)
            throw new ArgumentNullException("key");
 
        int hash = _Comparer.GetHashCode(key) & 2147483647;
        int index = hash % _Buckets.Length;
        int num = -1;
        for (int i = _Buckets[index]; i >= 0; i = _Next[i])
        {
            if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key))
            {
                if (num < 0)
                    _Buckets[index] = _Next[i];
                else
                    _Next[num] = _Next[i];
 
                _HashCodes[i] = -1;
                _Next[i] = _FreeList;
                _Keys[i] = default(TKey);
                _Values[i] = default(TValue);
                _FreeList = i;
                _FreeCount++;
                _Version++;
                return true;
            }
            num = i;
        }
        return false;
    }
 
    private void Insert(TKey key, TValue value, bool add)
    {
        if (key == null)
            throw new ArgumentNullException("key");
 
        if (_Buckets == null)
            Initialize(0);
 
        int hash = _Comparer.GetHashCode(key) & 2147483647;
        int index = hash % _Buckets.Length;
        int num1 = 0;
        for (int i = _Buckets[index]; i >= 0; i = _Next[i])
        {
            if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key))
            {
                if (add)
                    throw new ArgumentException("Key already exists: " + key);
 
                _Values[i] = value;
                _Version++;
                return;
            }
            num1++;
        }
        int num2;
        if (_FreeCount > 0)
        {
            num2 = _FreeList;
            _FreeList = _Next[num2];
            _FreeCount--;
        }
        else
        {
            if (_Count == _Keys.Length)
            {
                Resize();
                index = hash % _Buckets.Length;
            }
            num2 = _Count;
            _Count++;
        }
        _HashCodes[num2] = hash;
        _Next[num2] = _Buckets[index];
        _Keys[num2] = key;
        _Values[num2] = value;
        _Buckets[index] = num2;
        _Version++;
 
        //if (num3 > 100 && HashHelpers.IsWellKnownEqualityComparer(comparer))
        //{
        //    comparer = (IEqualityComparer<TKey>)HashHelpers.GetRandomizedEqualityComparer(comparer);
        //    Resize(entries.Length, true);
        //}
    }
 
    private void Initialize(int capacity)
    {
        int prime = PrimeHelper.GetPrime(capacity);
 
        _Buckets = new int[prime];
        for (int i = 0; i < _Buckets.Length; i++)
            _Buckets[i] = -1;
 
        _Keys = new TKey[prime];
        _Values = new TValue[prime];
        _HashCodes = new int[prime];
        _Next = new int[prime];
 
        _FreeList = -1;
    }
 
    private int FindIndex(TKey key)
    {
        if (key == null)
            throw new ArgumentNullException("key");
 
        if (_Buckets != null)
        {
            int hash = _Comparer.GetHashCode(key) & 2147483647;
            for (int i = _Buckets[hash % _Buckets.Length]; i >= 0; i = _Next[i])
            {
                if (_HashCodes[i] == hash && _Comparer.Equals(_Keys[i], key))
                    return i;
            }
        }
        return -1;
    }
 
    public bool TryGetValue(TKey key, out TValue value)
    {
        int index = FindIndex(key);
        if (index >= 0)
        {
            value = _Values[index];
            return true;
        }
        value = default(TValue);
        return false;
    }
 
    private static class PrimeHelper
    {
        public static readonly int[] Primes = new int[]
        {
            3,
            7,
            11,
            17,
            23,
            29,
            37,
            47,
            59,
            71,
            89,
            107,
            131,
            163,
            197,
            239,
            293,
            353,
            431,
            521,
            631,
            761,
            919,
            1103,
            1327,
            1597,
            1931,
            2333,
            2801,
            3371,
            4049,
            4861,
            5839,
            7013,
            8419,
            10103,
            12143,
            14591,
            17519,
            21023,
            25229,
            30293,
            36353,
            43627,
            52361,
            62851,
            75431,
            90523,
            108631,
            130363,
            156437,
            187751,
            225307,
            270371,
            324449,
            389357,
            467237,
            560689,
            672827,
            807403,
            968897,
            1162687,
            1395263,
            1674319,
            2009191,
            2411033,
            2893249,
            3471899,
            4166287,
            4999559,
            5999471,
            7199369
        };
 
        public static bool IsPrime(int candidate)
        {
            if ((candidate & 1) != 0)
            {
                int num = (int)Math.Sqrt((double)candidate);
                for (int i = 3; i <= num; i += 2)
                {
                    if (candidate % i == 0)
                    {
                        return false;
                    }
                }
                return true;
            }
            return candidate == 2;
        }
 
        public static int GetPrime(int min)
        {
            if (min < 0)
                throw new ArgumentException("min < 0");
 
            for (int i = 0; i < PrimeHelper.Primes.Length; i++)
            {
                int prime = PrimeHelper.Primes[i];
                if (prime >= min)
                    return prime;
            }
            for (int i = min | 1; i < 2147483647; i += 2)
            {
                if (PrimeHelper.IsPrime(i) && (i - 1) % 101 != 0)
                    return i;
            }
            return min;
        }
 
        public static int ExpandPrime(int oldSize)
        {
            int num = 2 * oldSize;
            if (num > 2146435069 && 2146435069 > oldSize)
            {
                return 2146435069;
            }
            return PrimeHelper.GetPrime(num);
        }
    }
 
   public ICollection<TKey> Keys
   {
        get { return _Keys.Take(Count).ToArray(); }
   }
 
   public ICollection<TValue> Values
   {
        get { return _Values.Take(Count).ToArray(); }
   }
 
    public void Add(KeyValuePair<TKey, TValue> item)
    {
        Add(item.Key, item.Value);
    }
 
    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        int index = FindIndex(item.Key);
        return index >= 0 &&
            EqualityComparer<TValue>.Default.Equals(_Values[index], item.Value);
    }
 
    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
    {
        if (array == null)
            throw new ArgumentNullException("array");
 
        if (index < 0 || index > array.Length)
            throw new ArgumentOutOfRangeException(string.Format("index = {0} array.Length = {1}", index, array.Length));
 
        if (array.Length - index < Count)
            throw new ArgumentException(string.Format("The number of elements in the dictionary ({0}) is greater than the available space from index to the end of the destination array {1}.", Count, array.Length));
 
        for (int i = 0; i < _Count; i++)
        {
            if (_HashCodes[i] >= 0)
                array[index++] = new KeyValuePair<TKey, TValue>(_Keys[i], _Values[i]);
        }
    }
 
    public bool IsReadOnly
    {
        get { return false; }
    }
 
    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        return Remove(item.Key);
    }
 
    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
 
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        return GetEnumerator();
    }
 
    public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
    {
        private readonly SerializableDictionary<TKey, TValue> _Dictionary;
        private int _Version;
        private int _Index;
        private KeyValuePair<TKey, TValue> _Current;
 
        public KeyValuePair<TKey, TValue> Current
        {
            get { return _Current; }
        }
 
        internal Enumerator(SerializableDictionary<TKey, TValue> dictionary)
        {
            _Dictionary = dictionary;
            _Version = dictionary._Version;
            _Current = default(KeyValuePair<TKey, TValue>);
            _Index = 0;
        }
 
        public bool MoveNext()
        {
            if (_Version != _Dictionary._Version)
                throw new InvalidOperationException(string.Format("Enumerator version {0} != Dictionary version {1}", _Version, _Dictionary._Version));
 
            while (_Index < _Dictionary._Count)
            {
                if (_Dictionary._HashCodes[_Index] >= 0)
                {
                    _Current = new KeyValuePair<TKey, TValue>(_Dictionary._Keys[_Index], _Dictionary._Values[_Index]);
                    _Index++;
                    return true;
                }
                _Index++;
            }
 
            _Index = _Dictionary._Count + 1;
            _Current = default(KeyValuePair<TKey, TValue>);
            return false;
        }
 
        void IEnumerator.Reset()
        {
            if (_Version != _Dictionary._Version)
                throw new InvalidOperationException(string.Format("Enumerator version {0} != Dictionary version {1}", _Version, _Dictionary._Version));
 
            _Index = 0;
            _Current = default(KeyValuePair<TKey, TValue>);
        }
 
        object IEnumerator.Current
        {
            get { return Current; }
        }
 
        public void Dispose()
        {
        }
    }
}

所以这是一个抽屉,不是最好的,但是嘿,它起作用了! -不支持将引用类型用作键(字符串除外) -您必须为制作的每种字典类型添加一个新的属性抽屉(请参见脚本的底部) -抽屉已开放供社区扩展,请感觉到免费改善它! -同样,为了更好地检查字典,请参阅我的框架。

[Serializable] public class MyDictionary1 : SerializableDictionary<string, int> { }
[Serializable] public class MyDictionary2 : SerializableDictionary<KeyCode, GameObject> { }
 
public class Test : MonoBehaviour
{
  public MyDictionary1 dictionary1;
  public MyDictionary2 dictionary2;
}
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityObject = UnityEngine.Object;
 
public abstract class DictionaryDrawer<TK, TV> : PropertyDrawer
{
    private SerializableDictionary<TK, TV> _Dictionary;
    private bool _Foldout;
    private const float kButtonWidth = 18f;
 
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        CheckInitialize(property, label);
        if (_Foldout)
            return (_Dictionary.Count + 1) * 17f;
        return 17f;
    }
 
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        CheckInitialize(property, label);
 
        position.height = 17f;
 
        var foldoutRect = position;
        foldoutRect.width -= 2 * kButtonWidth;
        EditorGUI.BeginChangeCheck();
        _Foldout = EditorGUI.Foldout(foldoutRect, _Foldout, label, true);
        if (EditorGUI.EndChangeCheck())
            EditorPrefs.SetBool(label.text, _Foldout);
 
        var buttonRect = position;
        buttonRect.x = position.width - kButtonWidth + position.x;
        buttonRect.width = kButtonWidth + 2;
 
        if (GUI.Button(buttonRect, new GUIContent("+", "Add item"), EditorStyles.miniButton))
        {
            AddNewItem();
        }
 
        buttonRect.x -= kButtonWidth;
 
        if (GUI.Button(buttonRect, new GUIContent("X", "Clear dictionary"), EditorStyles.miniButtonRight))
        {
            ClearDictionary();
        }
 
        if (!_Foldout)
            return;
 
        foreach (var item in _Dictionary)
        {
            var key = item.Key;
            var value = item.Value;
 
            position.y += 17f;
 
            var keyRect = position;
            keyRect.width /= 2;
            keyRect.width -= 4;
            EditorGUI.BeginChangeCheck();
            var newKey = DoField(keyRect, typeof(TK), key);
            if (EditorGUI.EndChangeCheck())
            {
                try
                {
                    _Dictionary.Remove(key);
                    _Dictionary.Add(newKey, value);
                }
                catch(Exception e)
                {
                    Debug.Log(e.Message);
                }
                break;
            }
 
            var valueRect = position;
            valueRect.x = position.width / 2 + 15;
            valueRect.width = keyRect.width - kButtonWidth;
            EditorGUI.BeginChangeCheck();
            value = DoField(valueRect, typeof(TV), value);
            if (EditorGUI.EndChangeCheck())
            {
                _Dictionary[key] = value;
                break;
            }
 
            var removeRect = valueRect;
            removeRect.x = valueRect.xMax + 2;
            removeRect.width = kButtonWidth;
            if (GUI.Button(removeRect, new GUIContent("x", "Remove item"), EditorStyles.miniButtonRight))
            {
                RemoveItem(key);
                break;
            }
        }
    }
 
    private void RemoveItem(TK key)
    {
        _Dictionary.Remove(key);
    }
 
    private void CheckInitialize(SerializedProperty property, GUIContent label)
    {
        if (_Dictionary == null)
        {
            var target = property.serializedObject.targetObject;
            _Dictionary = fieldInfo.GetValue(target) as SerializableDictionary<TK, TV>;
            if (_Dictionary == null)
            {
                _Dictionary = new SerializableDictionary<TK, TV>();
                fieldInfo.SetValue(target, _Dictionary);
            }
 
            _Foldout = EditorPrefs.GetBool(label.text);
        }
    }
 
    private static readonly Dictionary<Type, Func<Rect, object, object>> _Fields =
        new Dictionary<Type,Func<Rect,object,object>>()
        {
            { typeof(int), (rect, value) => EditorGUI.IntField(rect, (int)value) },
            { typeof(float), (rect, value) => EditorGUI.FloatField(rect, (float)value) },
            { typeof(string), (rect, value) => EditorGUI.TextField(rect, (string)value) },
            { typeof(bool), (rect, value) => EditorGUI.Toggle(rect, (bool)value) },
            { typeof(Vector2), (rect, value) => EditorGUI.Vector2Field(rect, GUIContent.none, (Vector2)value) },
            { typeof(Vector3), (rect, value) => EditorGUI.Vector3Field(rect, GUIContent.none, (Vector3)value) },
            { typeof(Bounds), (rect, value) => EditorGUI.BoundsField(rect, (Bounds)value) },
            { typeof(Rect), (rect, value) => EditorGUI.RectField(rect, (Rect)value) },
        };
 
    private static T DoField<T>(Rect rect, Type type, T value)
    {
        Func<Rect, object, object> field;
        if (_Fields.TryGetValue(type, out field))
            return (T)field(rect, value);
 
        if (type.IsEnum)
            return (T)(object)EditorGUI.EnumPopup(rect, (Enum)(object)value);
 
        if (typeof(UnityObject).IsAssignableFrom(type))
            return (T)(object)EditorGUI.ObjectField(rect, (UnityObject)(object)value, type, true);
 
        Debug.Log("Type is not supported: " + type);
        return value;
    }
 
    private void ClearDictionary()
    {
        _Dictionary.Clear();
    }
 
    private void AddNewItem()
    {
        TK key;
        if (typeof(TK) == typeof(string))
            key = (TK)(object)"";
        else key = default(TK);
 
        var value = default(TV);
        try
        {
            _Dictionary.Add(key, value);
        }
        catch(Exception e)
        {
            Debug.Log(e.Message);
        }
    }
}
 
[CustomPropertyDrawer(typeof(MyDictionary1))]
public class MyDictionaryDrawer1 : DictionaryDrawer<string, int> { }
 
[CustomPropertyDrawer(typeof(MyDictionary2))]
public class MyDictionaryDrawer2 : DictionaryDrawer<KeyCode, GameObject> { }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UnityInspector编辑`List<KeyValuePair>`可以使用自定义的PropertyDrawer来实现。下面是一些步骤来帮助你完成这个过程: 1. 创建一个新的脚本文件,命名为`KeyValuePairListDrawer.cs`(或者你喜欢的其他名称)。 2. 在脚本文件编写以下代码: ```csharp using UnityEngine; using UnityEditor; using System.Collections.Generic; [CustomPropertyDrawer(typeof(List<KeyValuePair<string, string>>))] public class KeyValuePairListDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { EditorGUI.BeginProperty(position, label, property); EditorGUI.LabelField(position, label); position.y += EditorGUIUtility.singleLineHeight; EditorGUI.indentLevel++; SerializedProperty list = property.FindPropertyRelative("list"); for (int i = 0; i < list.arraySize; i++) { SerializedProperty element = list.GetArrayElementAtIndex(i); SerializedProperty key = element.FindPropertyRelative("Key"); SerializedProperty value = element.FindPropertyRelative("Value"); Rect keyRect = new Rect(position.x, position.y, position.width * 0.4f, EditorGUIUtility.singleLineHeight); Rect valueRect = new Rect(position.x + position.width * 0.45f, position.y, position.width * 0.4f, EditorGUIUtility.singleLineHeight); EditorGUI.PropertyField(keyRect, key, GUIContent.none); EditorGUI.PropertyField(valueRect, value, GUIContent.none); position.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; } EditorGUI.indentLevel--; EditorGUI.EndProperty(); } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { int count = property.FindPropertyRelative("list").arraySize; return EditorGUIUtility.singleLineHeight * (count + 1) + EditorGUIUtility.standardVerticalSpacing * count; } } ``` 3. 将脚本文件放置在项目的任何文件夹。 4. 在Inspector使用`List<KeyValuePair<string, string>>`类型的属性时,它将自动使用我们创建的PropertyDrawer进行绘制和编辑。 现在,你可以在Inspector编辑`List<KeyValuePair<string, string>>`类型的属性了。每个KeyValuePair都会显示为一个键值对,并且你可以为每个键和值输入不同的值。 注意:这个PropertyDrawer只支持`List<KeyValuePair<string, string>>`类型的属性。如果你想在Inspector编辑其他类型的KeyValuePair列表,你需要进行适当的修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值