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

SwiftUI如何实现点击清空按钮重置List中所有Toggle为未选中状态

界面效果参考:
界面效果示意图

问题根因

你的清空逻辑不生效是两个核心问题导致的:

  • ListSection、RowItem都是结构体(值类型),你在按钮回调里写for var item in section.items拿到的是item的临时拷贝,修改拷贝不会影响原数组里的真实数据
  • ExpandableList里用@State声明了本地items变量,相当于把父视图传进来的数据复制了一份存在子视图本地,你在父视图/模型层改数据完全同步不到子视图的本地状态上,Toggle自然不会重置

修改步骤

1. 调整数据模型定义

把ListSection里的items属性从常量改成变量,支持后续修改:

struct ListSection: Identifiable, Equatable {
    static func == (lhs: ListSection, rhs: ListSection) -> Bool {
        lhs.id == rhs.id
    }
    
    let id = UUID()
    let title: String
    var items: [RowItem] // 原let声明改为var
    let visible: Int
}

2. 在HomeModel中新增清空方法

直接在视图模型层修改@Published标记的数据源,改动会自动触发视图刷新,不要在视图层遍历值拷贝:

class HomeModel: ObservableObject {
    // 原有items1、items2、sections、init代码保留不变
    // ...
    
    // 新增全局清空方法
    func clearAllSelections() {
        for sectionIndex in sections.indices {
            for itemIndex in sections[sectionIndex].items.indices {
                sections[sectionIndex].items[itemIndex].isSelected = false
            }
        }
    }
}

3. 修改ExpandableList的状态定义

把本地@State的items改成@Binding,直接绑定上层的真实数据源,不存本地拷贝:

struct ExpandableList: View {
    private var title: String
    private var visibleElements: Int
    private var showAllButtonVisible: Bool
    
    @Binding var items: [RowItem] // 原@State声明改为@Binding
    @State private var isExpanded = false
    
    init(title: String, items: Binding<[RowItem]>, visible: Int) { // 入参改为Binding类型
        self.title = title.lowercased()
        self._items = items // 绑定赋值
        self.visibleElements = visible
        self.showAllButtonVisible = visible < items.wrappedValue.count
    }
    
    // 原有body内的交互逻辑不需要改动,直接保留
    var body: some View {
        List {
            ForEach(isExpanded ? 0..<items.count : 0..<Array(items[0..<visibleElements]).count, id: \.self) { index in
                HStack {
                    Text(items[index].rowName).fontWeight(.light)
                    Spacer()
                    Text("\(items[index].amount)").foregroundColor(.gray).fontWeight(.light)
                    Toggle(isOn: Binding(
                        get: { return items[index].isSelected },
                        set: { items[index].isSelected = $0 }
                    )){}.toggleStyle(.checklist)
                }.listRowSeparator(.hidden)
            }
            
            if showAllButtonVisible {
                HStack {
                    Button {
                        withAnimation {
                            isExpanded.toggle()
                        }
                    } label: {
                        if isExpanded {
                            Label("Show less \(title)", systemImage: "chevron.up").foregroundColor(Color(red: 55/255, green: 126/255, blue: 83/255, opacity: 1)).labelStyle(ImageToRightSideLabelStyle())
                        } else {
                            Label("Show all \(title)", systemImage: "chevron.down").foregroundColor(Color(red: 55/255, green: 126/255, blue: 83/255, opacity: 1)).labelStyle(ImageToRightSideLabelStyle())
                        }
                    }
                }
            }
        }
    }
}

4. 调整MyForm里的传参和清空按钮逻辑

调用ExpandableList的时候传入绑定值,清空按钮直接调用模型的清空方法:

struct MyForm: View {
    @ObservedObject var model = HomeModel()
    
    var body: some View {
        NavigationView {
            VStack {
                Form {
                    ForEach($model.sections, id: \.id) { $section in // 遍历带绑定的sections数组
                        Section {
                            // 传入$section.items绑定值
                            ExpandableList(title: section.title, items: $section.items, visible: section.visible)
                        } header: {
                            Text(section.title).font(.title3).foregroundColor(.black).textCase(nil)
                        } footer: {
                            if section != model.sections.last {
                                VStack {
                                    Divider().padding(.top, 15)
                                }
                            }

                        }
                        
                    }
                }.navigationTitle(Text("Filter stocks"))
                
                HStack {
                    Button {
                        // 直接调用模型层的清空方法
                        model.clearAllSelections()
                    } label: {
                        Text("Clear filters").foregroundColor(.black)
                    }.padding(.leading, 30)
                    Spacer()
                    Button(action: {
                        print("sign up bin tapped")
                    }) {
                        Text("Show 1506 assets")
                            .font(.system(size: 18))
                            .padding()
                            .foregroundColor(.black)
                    }
                    .background(Color.green)
                    .cornerRadius(10)
                    .padding(.trailing, 30)
                }
            }

        }
    }
}

效果说明

改完之后:

  • 单个Toggle切换会直接修改HomeModel里的真实数据,不会出现子视图状态和上层不同步的问题
  • 点击清空按钮会直接修改模型层的所有选中状态,所有绑定了数据源的Toggle会自动刷新为未选中状态
  • 原有展开/收起列表的逻辑不受影响

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 20:48:35