在UIKit中,您可以使用allowsMultipleSelection选择UITableView的多行-可以使用SwiftUI中的列表来完成此操作吗?
答案 0 :(得分:5)
目前在SwiftUI中获得多项选择的唯一方法是使用EditButton
。但是,这不是您可能要使用多重选择的唯一实例,如果您实际上没有尝试编辑任何内容时使用EditButton
多重选择,则可能会使用户感到困惑。
我认为您真正想要的是这样的东西:
下面是我为此创建的代码:
struct MultipleSelectionList: View {
@State var items: [String] = ["Apples", "Oranges", "Bananas", "Pears", "Mangos", "Grapefruit"]
@State var selections: [String] = []
var body: some View {
List {
ForEach(self.items.identified(by: \.self)) { item in
MultipleSelectionRow(title: item, isSelected: self.selections.contains(item)) {
if self.selections.contains(item) {
self.selections.removeAll(where: { $0 == item })
}
else {
self.selections.append(item)
}
}
}
}
}
}
struct MultipleSelectionRow: View {
var title: String
var isSelected: Bool
var action: () -> Void
var body: some View {
Button(action: self.action) {
HStack {
Text(self.title)
if self.isSelected {
Spacer()
Image(systemName: "checkmark")
}
}
}
}
}
答案 1 :(得分:2)
我发现了一种使用自定义属性包装器的方法,该方法可以使用Binding
从子视图中修改选择内容:
struct Fruit: Selectable {
let name: String
var isSelected: Bool
var id: String { name }
}
struct FruitList: View {
@State var fruits = [
Fruit(name: "Apple", isSelected: true),
Fruit(name: "Banana", isSelected: false),
Fruit(name: "Kumquat", isSelected: true),
]
var body: some View {
VStack {
Text("Number selected: \(fruits.filter { $0.isSelected }.count)")
BindingList(items: $fruits) {
FruitRow(fruit: $0)
}
}
}
struct FruitRow: View {
@Binding var fruit: Fruit
var body: some View {
Button(action: { self.fruit.isSelected.toggle() }) {
HStack {
Text(fruit.isSelected ? "☑" : "☐")
Text(fruit.name)
}
}
}
}
}
答案 2 :(得分:2)
这是使用我创建的名为Multiselect
的助手的另一种方法:
struct Fruit: Selectable {
let name: String
var isSelected: Bool
var id: String { name }
}
struct FruitList: View {
@State var fruits = [
Fruit(name: "Apple", isSelected: true),
Fruit(name: "Banana", isSelected: false),
Fruit(name: "Kumquat", isSelected: true),
]
var body: some View {
VStack {
Text("Number selected: \(fruits.filter { $0.isSelected }.count)")
Multiselect(items: $fruits) { fruit in
HStack {
Text(fruit.name)
Spacer()
if fruit.isSelected {
Image(systemName: "checkmark")
}
}
}
}
}
}
此处提供了支持代码:
protocol Selectable: Identifiable {
var name: String { get }
var isSelected: Bool { get set }
}
struct Multiselect<T: Selectable, V: View>: View {
@Binding var items: [T]
var rowBuilder: (T) -> V
var body: some View {
List(items) { item in
Button(action: { self.items.toggleSelected(item) }) {
self.rowBuilder(item)
}
}
}
}
extension Array where Element: Selectable {
mutating func toggleSelected(_ item: Element) {
if let index = firstIndex(where: { $0.id == item.id }) {
var mutable = item
mutable.isSelected.toggle()
self[index] = mutable
}
}
}
答案 3 :(得分:2)
我的 2 美分一个超级简单的解决方案:
import SwiftUI
struct ListDemo: View {
@State var items = ["Pizza", "Spaghetti", "Caviar"]
@State var selection = Set<String>()
var body: some View {
List(items, id: \.self, selection: $selection) { (item : String) in
let s = selection.contains(item) ? "√" : " "
HStack {
Text(s+item)
Spacer()
}
.contentShape(Rectangle())
.onTapGesture {
if selection.contains(item) {
selection.remove(item)
}
else{
selection.insert(item)
}
print(selection)
}
}
.listStyle(GroupedListStyle())
}
}
在集合中使用字符串是次优的,最好使用 id 或使用带有数据和选择状态的字符串。
答案 4 :(得分:1)
我创建了一个自定义ToggleStyle
,如下所示:
import SwiftUI
enum Fruit: String, CaseIterable, Hashable {
case apple = "Apple"
case orange = "Orange"
case banana = "Banana"
}
struct ContentView: View {
@State var fruits = [Bool](repeating: false, count: Fruit.allCases.count)
var body: some View {
Form{
ForEach(0..<fruits.count, id:\.self){i in
Toggle(isOn: self.$fruits[i]){
Text(Fruit.allCases[i].rawValue)
}.toggleStyle(CheckmarkToggleStyle())
}
}
}
}
struct CheckmarkToggleStyle: ToggleStyle {
func makeBody(configuration: Self.Configuration) -> some View {
HStack {
Button(action: { withAnimation { configuration.$isOn.wrappedValue.toggle() }}){
HStack{
configuration.label.foregroundColor(.primary)
Spacer()
if configuration.isOn {
Image(systemName: "checkmark").foregroundColor(.primary)
}
}
}
}
}
}
答案 5 :(得分:0)
首先将其添加到您的视图
@State var selectedItems = Set<UUID>()
Set
的类型取决于您用来id:
中的项目ForEach
的类型
接下来声明列表
List(selection: $selectedItems) {
ForEach(items, id: \.id) { item in
Text("\(item.name)")
}
}
现在,您选择的任何内容都会添加到selectedItems Set
中,使用后请记住将其清除。