删除具有绑定布尔值的列表项 - 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
我需要更改什么才能删除项目?我应该对 Toggle
的 Binding
问题采取不同的方法吗?
我建议您将 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)
}
总之,我没有更改绑定值的值,因此我没有收到任何错误!
在我的应用程序中,我有一个屏幕,用户可以在其中使用 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
我需要更改什么才能删除项目?我应该对 Toggle
的 Binding
问题采取不同的方法吗?
我建议您将 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)
}
总之,我没有更改绑定值的值,因此我没有收到任何错误!