删除具有绑定布尔值的列表项 - SwiftUI

Deleting List Item With A Binding Boolean Value - SwiftUI

在我的应用程序中,我有一个屏幕,用户可以在其中使用 Swift Toggle 打开和关闭(地图的)过滤器,还可以删除它们(使用 Edit Button).我使用 Binding 布尔变量来连接切换,以便我可以对每个更改做出反应,代码如下:

//The filter data model
class DSFilter{
    
    var filterId : Int
    var filterTitle : String
    var isActive : Bool
    
    
    init(filterId : Int, filterTitle : String, isActive : Bool){
        self.filterId = filterId
        self.filterTitle = filterTitle
        self.isActive = isActive
    }
}

//The data model representable
struct filterItem : View {
    @Binding var filter : DSFilter
    @Binding var isOn : Bool
    @State var image = Image("defPerson")
    
    var body : some View {
        HStack {
            image.resizable().frame(width: 45, height: 45).clipShape(Circle())
            VStack(alignment: .leading, spacing: 8) {
                Text(filter.filterTitle).font(Font.custom("Quicksand-Bold",size: 15))
                Text(filter.filterTitle).font(Font.custom("Quicksand-Medium",size: 13)).foregroundColor(.gray)
            }.padding(.leading)
            Spacer()
            HStack{
                Toggle("",isOn: $isOn).padding(.trailing, 5).onReceive([self.isOn].publisher.first()) { (value) in
                    self.filter.isActive = self.isOn
                }.frame(width: 30)
            }
        }.frame(height: 60)
            .onAppear(){
                self.isOn = self.filter.isActive             
        }
    }
}

//The view where the user has the control
struct FilterView: View {
    @State var otherFilters : [addedFilter] = []
    @Binding var isActive : Bool
    
    var body: some View {
        VStack{
            Capsule().fill(Color.black).frame(width: 50, height: 5).padding()
            ZStack{
                HStack{
                    Spacer()

                    Text("Filters").font(Font.custom("Quicksand-Bold", size: 20))

                    Spacer()
                }.padding()
                HStack{
                    Spacer()
                    
                    EditButton()
                    
                }.padding()
            }

                List{
                    
                    ForEach(0..<self.otherFilters.count, id:\.self){ i in
                        
                        filterItem(filter: self.$otherFilters[i].filter, isOn: self.$otherFilters[i].isOn)
                    }.onDelete(perform:removeRows)
                   
   
                
            }
            Spacer()
        }
        
    }
    
    func removeRows(at offsets: IndexSet) {
        print("deleting")
                    print("deleted filter!")
            self.otherFilters.remove(at: Array(offsets)[0]) //I use it like so because you can only delete 1 at a time anyway
       
        
    }
}

//The class I use to bind the isOn value so I can react to change
struct addedFilter : Identifiable{
    var id : Int
    var filter : DSFilter
    var isOn : Bool
    
    init(filter : DSFilter){
        self.id = Int.random(in: 0...100000)
        self.filter = filter
        self.isOn = filter.isActive
    }
}

当我按原样使用删除时,出现以下错误 (Xcode 12.0):

Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
2020-10-06 17:42:12.567235+0300 Hynt[5207:528572] Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444

我需要更改什么才能删除项目?我应该对 ToggleBinding 问题采取不同的方法吗?

我建议您将 removeRows() 函数中的行从

更改为
self.otherFilters.remove(at: Array(offsets)[0]

self.otherFilters.remove(atOffsets: offsets) 

您好,不要保留三个不同的数组来管理 addedFilter、DSFilter、isOn。为什么不尝试以下 一个单一模型

class FFilter: Identifiable {
var id: Int
 var addedFilter: addedFilter
var dsFilter: DSFilter
var isOn: Bool

init(addedFilter: addedFilter, dsFilter: DSFilter, isOn: Bool) {
    self.id = addedFilter.id
    self.addedFilter = addedFilter
    self.dsFilter = dsFilter
    self.isOn = isOn
}

}

ViewModel 更改代码如下:

class ViewModel: ObservableObject {

@Published var superFilters: [FFilter] = [
    FFilter(
        addedFilter: addedFilter(
            filter: DSFilter(filterId: 1, filterTitle: "Title1", isActive: true)
        ),
        dsFilter: DSFilter(filterId: 1, filterTitle: "Title1", isActive: true),
        isOn: true),
    FFilter(
        addedFilter: addedFilter(
            filter: DSFilter(filterId: 2, filterTitle: "Title2", isActive: false)
        ),
        dsFilter: DSFilter(filterId: 2, filterTitle: "Title2", isActive: false),
        isOn: false),
    FFilter(
        addedFilter: addedFilter(filter: DSFilter(filterId: 3, filterTitle: "Title3", isActive: true)),
        dsFilter: DSFilter(filterId: 3, filterTitle: "Title3", isActive: true),
        isOn: true),
    FFilter(
        addedFilter: addedFilter(
            filter: DSFilter(filterId: 4, filterTitle: "Title4", isActive: true)
        ),
        dsFilter: DSFilter(filterId: 4, filterTitle: "Title4", isActive: true),
        isOn: true),
    FFilter(
        addedFilter: addedFilter(
            filter: DSFilter(filterId: 5, filterTitle: "Title5", isActive: false)
        ),
        dsFilter: DSFilter(filterId: 5, filterTitle: "Title5", isActive: false),
        isOn: false)
]}

然后更改您的列表代码

  List {
 ForEach(viewModel.superFilters) { filter in
      filterItem(filter: .constant(filter.dsFilter), isOn: .constant(filter.isOn))
      }.onDelete(perform: removeRows(at:)) }

和 removeRows 方法:

func removeRows(at offsets: IndexSet) {
    print("deleting at \(offsets)")
    self.viewModel.superFilters.remove(atOffsets: offsets)}

希望能奏效。如果您仍然遇到任何问题,请告诉我

所以,在多次尝试和失败之后,我找到了答案。 问题似乎出在绑定部分——如果我从中绑定一个元素,编译器无法处理数组大小的变化,所以我做了以下操作: 首先,我更改了 filterItem struct,因此过滤器 属性 是 @State 而不是 @Binding :

struct filterItem : View {
    @State var filter : DSFilter
    @Binding var isOn : Bool

其次,我已将 addedFilter struct 更改为以下内容:

struct addedFilter : Identifiable{
    var id : Int
    var isOn : Bool
    
    init(filter : DSFilter){
        self.id = filter.filterId
        self.isOn = filter.isActive
    }
}

并且 ForEach 循环到以下内容:

ForEach(0..<self.normOthFilters.count, id:\.self){ i in
                        filterItem(filter: self.normOthFilters[i], isOn: self.$otherFilters[i].isOn)
                    }.onDelete(perform:removeRows)

我在主视图中添加了:

    @State var normDefFilters : [DSFilter] = []
    @State var normOthFilters : [DSFilter] = []

最后是以下的 onDelete 函数:

func removeRows(at offsets: IndexSet) {
        print("deleting")
            print("deleted filter!")
            self.normOthFilters.remove(atOffsets: offsets)
        
    }

总之,我没有更改绑定值的值,因此我没有收到任何错误!