Unity自定义属性抽屉问题:下拉菜单修改时数组内所有元素值同步变更
Unity自定义属性抽屉问题:下拉菜单修改时数组内所有元素值同步变更
嘿,我来帮你搞定这个头疼的问题!你遇到的所有元素同步变更的情况,根源在于自定义属性抽屉的成员变量被多个属性实例共享了,咱们一步步拆解解决:
问题原因分析
你在SoundNamePropertyDrawer里把_nameProperty、_indexProperty这些属性引用定义成了类的成员变量,但Unity的CustomPropertyDrawer实例是会被复用的——比如当你在数组里有多个SoundName元素时,所有元素的绘制工作都会用同一个Drawer实例。
这就会导致:当绘制第二个元素时,_nameProperty会被替换成第二个元素的Name属性引用,之前的元素再刷新时,用的已经是新的引用了,结果就是所有元素的属性值都被同步成最后一次修改的那个值。
解决方案:避免成员变量共享属性引用
核心修改点就是:不要把每个属性独有的SerializedProperty存在Drawer的实例成员变量里,而是每次OnGUI调用时,都基于传入的property参数重新获取对应的子属性。另外资源加载部分可以用静态变量做缓存(因为资源是全局唯一的),避免重复加载。
修改后的完整代码示例:
using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(SoundName))] public class SoundNamePropertyDrawer : PropertyDrawer { // 用静态变量缓存资源,避免重复加载(全局唯一,不会有共享问题) private static SoundNamesContainer _soundNamesContainer; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // 每次绘制都从当前传入的property获取子属性,确保对应当前要绘制的元素 SerializedProperty nameProperty = property.FindPropertyRelative("Name"); SerializedProperty indexProperty = property.FindPropertyRelative("index"); // 加载资源(静态变量只会初始化一次) if (_soundNamesContainer == null) { _soundNamesContainer = Resources.Load<SoundNamesContainer>("SoundNames"); if (_soundNamesContainer == null) { Debug.LogError("找不到Resources目录下的SoundNames资源!"); return; } } // 这里写你的下拉菜单逻辑,比如用EditorGUI.Popup string[] soundOptions = _soundNamesContainer.soundNames; // 假设你的容器类里有这个字符串数组 int currentIndex = indexProperty.intValue; // 确保索引在有效范围内,防止越界 if (currentIndex < 0 || currentIndex >= soundOptions.Length) { currentIndex = 0; indexProperty.intValue = currentIndex; nameProperty.stringValue = soundOptions[currentIndex]; } // 绘制下拉菜单并更新值 currentIndex = EditorGUI.Popup(position, label.text, currentIndex, soundOptions); if (currentIndex != indexProperty.intValue) { indexProperty.intValue = currentIndex; nameProperty.stringValue = soundOptions[currentIndex]; } } // 可选:重写这个方法设置属性行的高度 public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { return EditorGUIUtility.singleLineHeight; } }
额外提示
- 如果你之前的下拉菜单逻辑有其他自定义处理,只需要把原来用到
_nameProperty、_indexProperty的地方,替换成本次OnGUI里新获取的局部变量即可。 - 静态变量
_soundNamesContainer是安全的,因为它缓存的是全局唯一的资源实例,所有属性绘制都用同一个资源,不会导致属性值混乱。
备注:内容来源于stack exchange,提问作者Stefan Carpeliuc




