Unity PropertyDrawer数组元素删除时如何取消SceneView绘制订阅?
Unity PropertyDrawer 数组元素移除检测方案
Unity 没有直接提供数组元素移除的事件通知给 PropertyDrawer,但可以通过以下几种简洁的方式实现检测与订阅取消:
1. 在 SceneView 回调中实时校验属性有效性
每次 SceneView.duringSceneGui 触发时,先检查关联的 SerializedProperty 是否仍处于有效状态,一旦失效就立即取消订阅:
private void OnSceneGUI(SceneView sceneView) { // 校验逻辑:判断序列化对象、目标对象是否存在,属性是否有效 if (serializedObject == null || serializedObject.targetObject == null || !property.IsValid()) { SceneView.duringSceneGui -= OnSceneGUI; return; } // 正常绘制 SceneView 内容 // ... }
注:
IsValid()是 Unity 2021.2+ 新增的 SerializedProperty 扩展方法;低版本可通过尝试访问property.propertyPath捕获异常,或检查属性的父数组是否存在且索引合法来判断有效性。
2. 借助 EditorApplication.update 做周期性轻量检测
如果担心 SceneView 回调触发不及时,可以同时订阅 EditorApplication.update,在每一帧做快速校验:
private void SubscribeEvents() { SceneView.duringSceneGui += OnSceneGUI; EditorApplication.update += CheckPropertyValidity; } private void CheckPropertyValidity() { bool isInvalid = serializedObject == null || serializedObject.targetObject == null || property == null || !property.IsValid(); if (isInvalid) { SceneView.duringSceneGui -= OnSceneGUI; EditorApplication.update -= CheckPropertyValidity; } }
3. 利用 PropertyDrawer 自身生命周期校验
在 PropertyDrawer 的 OnGUI 方法中,每次绘制时检查当前属性是否还属于父数组,一旦发现元素已被移除就取消订阅:
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { base.OnGUI(position, property, label); bool isPropertyValid = true; try { // 解析父数组路径并检查索引合法性 var parentPath = property.propertyPath.Split('.')[0]; var parentArray = property.serializedObject.FindProperty(parentPath); isPropertyValid = parentArray != null && property.arrayIndex < parentArray.arraySize; } catch { isPropertyValid = false; } if (!isPropertyValid) { SceneView.duringSceneGui -= OnSceneGUI; } }
这种方法无需额外上下文对象,直接依托 PropertyDrawer 的绘制周期完成校验,适合简单场景。
内容的提问来源于stack exchange,提问作者zORg Alex
相关产品推荐
相关产品推荐

