HStack{
ForEach($rs.newsCategoryCollection){ $category in
Toggle(category.id, isOn: $category.isSelected)
.toggleStyle(.button)
.onChange(of: category.isSelected) {value in
print("Changed")
if value{
rs.unselectOtherCategory(id: category.id)
print("Selected: \(category.id)")
viewModel.loadNews()
}else{
category.isSelected = true
print("Deselected: \(category.id)")
}
}
}
}
在这里,我尝试在水平视图中设置切换按钮。我希望将其用作选择器,一次仅选择一个类别。
因此,在用户选择任何一个类别后,应使用此方法取消选择另一个类别:
rs.unselectOtherCategory(id: category.id)
所以我使用 onChange 通过跟踪值的变化来检测用户选择类别。但是使用前面的方法取消选择所有其他类别会更改先前选择的类别的值并再次调用 onChange。
当我使用 else 块来确保如果用户点击选定的按钮并取消选择(这使得所有按钮都被取消选择)时,问题会变得更加复杂,else 块可以对抗它并选择唯一选定的按钮。
如何避免重复调用 onChange。
我希望用户能够点击一个按钮并选择它,其他按钮将被取消选择。但是,如果用户点击已选择的按钮,则该按钮将保持选中状态。
这看起来更像是一个
Picker
,而不是一组 Toggle
。当您希望一次选择一项时,请勿使用 Toggle
。
您可以将
Toggle
更改为 Button
:
HStack{
ForEach($rs.newsCategoryCollection){ $category in
Button(category.id) {
if !category.isSelected {
category.isSelected = true
rs.unselectOtherCategory(id: category.id)
viewModel.loadNews()
}
}
.padding(8)
.background(.accent.opacity(category.isSelected ? 0.1 : 0), in: RoundedRectangle(cornerRadius: 10))
}
}
也就是说,我建议使用
Picker
,带有 .segmented
选择器样式,看起来类似于一排按钮。
struct ContentView: View {
@State var rs = ...
@State var selectedCategory: NewsCategory.ID = "" // assuming NewsCategory.ID is a String
var body: some View {
Picker(selection: $selectedCategory) {
ForEach(rs.newsCategoryCollection){ category in
Text(category.id)
}
} label: {
}
.pickerStyle(.segmented)
.onChange(of: selectedCategory) {
viewModel.loadNews()
}
}
}
现在您甚至不需要
isSelected
中的 NewsCategory
属性。如果出于某种原因确实需要它,可以向 selectCategory
添加 rs
方法,例如
// selectCategory could be implemented as:
mutating func selectCategory(id: String) {
for i in newsCategoryCollection.indices {
if newsCategoryCollection[i].id != id {
newsCategoryCollection[i].isSelected = false
} else {
newsCategoryCollection[i].isSelected = true
}
}
}
然后在
onChange
中调用它。