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

SwiftUI递归使用DisclosureGroup时视图更新异常如何解决?

问题原因
  • SwiftUI的List存在单元格复用机制,同位置的视图在数据源切换时会默认复用之前的视图状态,你的两个数据源结构高度相似,导致DisclosureGroup的展开状态、内容绘制没有同步更新到新数据源的对应值
  • 你当前Item模型中的isExpanded使用了.constant绑定,属于只读固定值,无法跟随数据源切换自动更新状态
  • 问题和id属性直接相关:SwiftUI通过视图的唯一标识判断是否需要销毁重建,你没有给切换的ContentView指定独立标识,导致系统判定为同一类视图触发复用
解决方案

方案1:快速修复(强制禁用视图复用)

直接给切换的ContentView添加id()修饰符,只要isChange状态变化,系统就会销毁旧视图,重新创建对应新数据源的视图,完全避免复用错乱,修改TestApp的List部分代码即可:

List {
    if isChange {
        ContentView(item: item)
            .id(isChange)
    } else {
        ContentView(item: item2)
            .id(isChange)
    }
}

方案2:规范数据绑定(推荐,可保留展开状态同步)

如果需要保留不同数据源各自的展开状态,需要修改模型和绑定逻辑:

  1. 修改Item模型,去掉@Binding包装,将isExpanded改为普通可变存储属性
struct Item: Identifiable {
    var id: UUID = UUID()
    var isExpanded: Bool = true
    var title: String = "title"
    var children: [Item] = []
    
    init(title: String, children: [Item]) {
        self.title = title
        self.children = children
        self.isExpanded = true
    }
}
  1. 在TestApp中用@State包装两个数据源,保证数据变化能触发视图更新
@State var item: Item = dummyItems
@State var item2: Item = dummyItems2
  1. 修改ContentView的ForEach为绑定遍历,让DisclosureGroup的展开状态和数据源属性一一绑定
struct ContentView: View {
    let item: Item
    
    var body: some View {
        // 用$前缀获取数组元素的绑定
        ForEach($item.children) { $item in
            if item.children.isEmpty {
                Text(item.title)
            } else {
                DisclosureGroup(
                    isExpanded: $item.isExpanded,
                    content: {
                        ContentView(item: item)
                    },
                    label: { Text(item.title) }
                )
            }
        }
    }
}
常见疑问解答
  • 能否控制视图的复用行为? 可以,id()修饰符就是SwiftUI提供的显式控制视图标识的接口,只要给视图绑定不同的id值,系统就会判定为不同视图,不会复用旧视图的状态和内容
  • 是否和id属性有关? 完全相关,SwiftUI的Diffing算法核心就是通过视图标识、结构、数据的变化判断是否需要更新、复用或重建视图,你当前的问题本质就是不同数据源的视图被判定为同一标识触发了复用

内容的提问来源于stack exchange,提问作者Park재현

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:45:04