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

如何在Unity编译代码或关闭窗口后保存UI Toolkit编辑器窗口值?

Unity UI Toolkit编辑器窗口值持久化方案

针对编译后编辑器窗口值丢失的问题,结合你用到的ListView及ObjectField/Vector3/Toggle元素,提供以下几种实用的持久化方案:

方案一:用EditorPrefs存储(适合简单数据场景)

EditorPrefs是Unity提供的编辑器全局存储工具,适合存储轻量数据,步骤如下:

  1. 给列表条目生成唯一键名:为避免键名冲突,给每个条目加窗口前缀+索引+元素类型,比如"MyWindow_ListItem_0_Object"。
  2. 监听元素变化并保存:给每个UI元素绑定值变更事件,实时将数据存入EditorPrefs:
    // ObjectField保存示例
    ObjectField objField = element.Q<ObjectField>();
    objField.valueChanged += newValue => {
        EditorPrefs.SetString($"MyWindow_ListItem_{index}_Object", EditorJsonUtility.ToJson(newValue));
    };
    
    // Vector3保存示例
    Vector3Field vec3Field = element.Q<Vector3Field>();
    vec3Field.valueChanged += newValue => {
        EditorPrefs.SetString($"MyWindow_ListItem_{index}_Vector3", JsonUtility.ToJson(newValue));
    };
    
    // Toggle保存示例
    Toggle toggle = element.Q<Toggle>();
    toggle.valueChanged += newValue => {
        EditorPrefs.SetBool($"MyWindow_ListItem_{index}_Toggle", newValue);
    };
    
  3. 窗口初始化时恢复数据:在ListView的BindItem方法中,根据索引读取EditorPrefs的值并赋值给元素:
    void BindItem(VisualElement element, int index) {
        // 恢复ObjectField
        var objField = element.Q<ObjectField>();
        var objJson = EditorPrefs.GetString($"MyWindow_ListItem_{index}_Object", "");
        if (!string.IsNullOrEmpty(objJson)) {
            objField.value = EditorJsonUtility.FromJson<Object>(objJson);
        }
    
        // 恢复Vector3Field
        var vec3Field = element.Q<Vector3Field>();
        var vec3Json = EditorPrefs.GetString($"MyWindow_ListItem_{index}_Vector3", "");
        if (!string.IsNullOrEmpty(vec3Json)) {
            vec3Field.value = JsonUtility.FromJson<Vector3>(vec3Json);
        }
    
        // 恢复Toggle
        var toggle = element.Q<Toggle>();
        toggle.value = EditorPrefs.GetBool($"MyWindow_ListItem_{index}_Toggle", false);
    }
    

方案二:用ScriptableObject作为数据容器(推荐复杂结构场景)

将列表数据存在ScriptableObject中,数据会被Unity持久化到Project目录,支持版本控制,步骤如下:

  1. 定义数据容器类:
    [CreateAssetMenu(fileName = "ListViewData", menuName = "Custom/ListView Data")]
    public class ListViewData : ScriptableObject {
        [System.Serializable]
        public class ListItemData {
            public Object targetObj;
            public Vector3 position;
            public bool isEnabled;
        }
        public List<ListItemData> items = new List<ListItemData>();
    }
    
  2. 在窗口中引用数据容器:可以在窗口顶部加一个ObjectField,让用户选择或创建ListViewData实例。
  3. 同步UI与数据容器:UI元素值变化时,更新容器数据并标记为脏(触发Unity保存):
    // 假设dataAsset是已引用的ListViewData实例
    objField.valueChanged += newValue => {
        dataAsset.items[index].targetObj = newValue;
        EditorUtility.SetDirty(dataAsset);
    };
    
  4. 初始化窗口时从容器读数据:遍历dataAsset.items,将数据填充到ListView的对应条目即可。
  5. 动态条目处理:添加/删除列表条目时,同步增删dataAsset.items中的数据项。

方案三:监听编译/退出事件主动保存

通过Unity编辑器事件,在编译开始或窗口关闭前主动保存数据,避免丢失:

void OnEnable() {
    // 监听编译开始事件
    CompilationPipeline.compilationStarted += OnCompilationStart;
    // 监听编辑器退出事件
    EditorApplication.quitting += SaveAllData;
}

void OnDisable() {
    // 移除事件监听
    CompilationPipeline.compilationStarted -= OnCompilationStart;
    EditorApplication.quitting -= SaveAllData;
}

void OnCompilationStart(object obj) {
    SaveAllData();
}

void SaveAllData() {
    // 遍历ListView所有条目,收集数据并保存(用EditorPrefs或ScriptableObject均可)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:13:30