You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中PropertyDrawer.GetPropertyHeight在数组元素变更时未被调用

Unity自定义曲线工具数组/列表元素切换时字段高度不刷新问题解决

问题背景

为解决曲线工具在数组中绘制的问题重写了工具,但在数组与列表元素的编辑器间切换时出现异常:已编辑元素会保留其高度,直到编辑集合内其他元素或曲线字段。尝试使用EditorUtility.SetDirty(targetObject)(搭配或不搭配EditorGUI.BeginChangeCheck()/EditorGUI.EndChangeCheck())均无法触发Unity刷新字段高度。

左侧数字为OtherCurve.z,用于区分调试的PropertyDrawer,标签为临时标签。

测试代码:

public class OtherTestScript : MonoBehaviour
{
    public OtherCurve curve;
    public OtherCurve[] curveArray;
    public List<OtherCurve> curveList;
}

问题相关代码需放入Assets/Plugins/,并在Packages/manifest.json中添加以下依赖:

"st.one-line": "https://github.com/slavniyteo/one-line.git#master",
"st.rect-ex": "https://github.com/slavniyteo/rect-ex.git#master",

问题原因

Unity Inspector会缓存PropertyDrawer的高度值,当切换数组/列表的元素编辑器时,Unity不会主动重新计算未修改元素的高度,导致之前编辑元素的高度被错误保留。EditorUtility.SetDirty仅标记对象需要保存,无法触发Inspector的布局刷新。

解决方案

1. 强制每次重新计算属性高度

在自定义PropertyDrawer的GetPropertyHeight方法中,通过生成唯一控制ID,强制Unity放弃高度缓存,每次都根据当前属性状态重新计算高度:

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
    // 生成唯一控制ID,强制Unity重新计算高度
    EditorGUIUtility.GetControlID(FocusType.Passive, property.propertyPath);
    
    // 替换为你的实际高度计算逻辑
    var curve = (OtherCurve)fieldInfo.GetValue(property.serializedObject.targetObject);
    return curve.IsExpanded ? 220f : 24f; // 示例:展开时高220,折叠时高24
}

2. 检测元素切换并触发Inspector重绘

在PropertyDrawer的OnGUI方法中,记录当前属性路径,当检测到路径变化(即切换了数组/列表元素)时,触发当前Inspector窗口重绘:

private string _lastPropertyPath;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    EditorGUI.BeginProperty(position, label, property);
    
    // 检测是否切换了数组/列表元素
    var currentPath = property.propertyPath;
    if (_lastPropertyPath != currentPath)
    {
        _lastPropertyPath = currentPath;
        // 触发当前聚焦的Inspector窗口重绘
        EditorWindow.focusedWindow?.Repaint();
    }

    // 你的原有绘制逻辑
    var curve = (OtherCurve)fieldInfo.GetValue(property.serializedObject.targetObject);
    // ... 绘制曲线、编辑字段的代码 ...

    EditorGUI.EndProperty();
}

3. 属性修改后触发全局重绘

若上述方法仍无效,可在属性修改完成后,通过延迟调用触发所有视图重绘,确保布局更新:

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
    EditorGUI.BeginChangeCheck();
    EditorGUI.BeginProperty(position, label, property);

    // 你的原有绘制逻辑
    var curve = (OtherCurve)fieldInfo.GetValue(property.serializedObject.targetObject);
    // ... 绘制代码 ...

    EditorGUI.EndProperty();
    if (EditorGUI.EndChangeCheck())
    {
        property.serializedObject.ApplyModifiedProperties();
        // 延迟调用避免当前布局周期内重绘冲突
        EditorApplication.delayCall += () => EditorApplication.RepaintAllViews();
    }
}

内容的提问来源于stack exchange,提问作者zORg Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:24:20