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

SwiftUI可变高度子视图列表占用额外空间问题求助

问题原因

SwiftUI的List底层依赖UIKit的UITableView实现,它会缓存单元格的高度来优化性能。当你展开Collapsible视图并添加item后,List会记录此时该单元格的高度;即使后续通过frame(maxHeight: 0)折叠视图,List的高度缓存并未同步更新——因为被折叠的视图只是被裁剪,其内部的VStack依然存在,视图的**固有内容尺寸(intrinsic content size)**还是保留了添加item后的高度,导致List依旧为该单元格预留空间。

解决方法

有两种可靠的解决思路,根据需求选择:


思路1:条件渲染折叠内容

直接在折叠状态下不渲染内部的VStack,彻底移除这部分视图的固有尺寸,让List能正确计算单元格高度。

修改Collapsible的代码:

struct Collapsible: View {
    @State private var isExpanded: Bool = false
    @State private var items: [String] = ["item1", "item2", "item3"]
    
    var body: some View {
        VStack {
            HStack {
                Text("Tap Me")
                Spacer()
                Text("Info")
            }
            .contentShape(Rectangle())
            .onTapGesture {
                isExpanded.toggle()
            }
            
            // 只有展开时才渲染内容
            if isExpanded {
                VStack {
                    ForEach(items, id: \.self) { item in
                        HStack {
                            Text("Item")
                            Spacer()
                            Text("Info")
                        }
                        .padding(.vertical, 5)
                    }
                    
                    Button("Add Item") {
                        items.append("new item")
                    }
                }
            }
        }
        .background(Color.cyan)
    }
}

思路2:强制List刷新单元格高度

通过给Collapsible视图添加动态ID,让List在折叠状态或items数量变化时,重新创建单元格并计算高度。

修改Collapsible的代码:

struct Collapsible: View {
    @State private var isExpanded: Bool = false
    @State private var items: [String] = ["item1", "item2", "item3"]
    
    var body: some View {
        VStack {
            HStack {
                Text("Tap Me")
                Spacer()
                Text("Info")
            }
            .contentShape(Rectangle())
            .onTapGesture {
                isExpanded.toggle()
            }
            
            VStack {
                ForEach(items, id: \.self) { item in
                    HStack {
                        Text("Item")
                        Spacer()
                        Text("Info")
                    }
                    .padding(.vertical, 5)
                }
                
                Button("Add Item") {
                    items.append("new item")
                }
            }
            .frame(maxHeight: isExpanded ? .none : 0)
            .clipped()
        }
        .background(Color.cyan)
        // 根据状态生成动态ID,触发List重新计算高度
        .id("\(isExpanded)-\(items.count)")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 05:12:12