SwiftUI 3 MacOs Таблица одиночного выбора и двойного щелчка по открытому листу

      import SwiftUI

struct ContentView: View {
    
    @State private var items: [ItemModel] = Array(0...100).map { ItemModel(id: $0, title: "item \($0)", age: $0) }
    @State private var selection = Set<ItemModel.ID>()
    @State private var sorting = [KeyPathComparator(\ItemModel.age)]
    
    var body: some View {
        Table(items, selection: $selection, sortOrder: $sorting) {
            TableColumn("id", value: \.id) { Text("\($0.id)") }
            TableColumn("title", value: \.title)
            TableColumn("age", value: \.age) { Text("\($0.age)") }
        }
        .onChange(of: sorting) {
            items.sort(using: $0)
        }
        .font(.caption)
        .frame(width: 960, height: 540)
    }
}

struct ItemModel: Identifiable {
    var id: Int
    var title: String
    var age: Int
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

это рабочий пример таблицы, отсортированной по Model.age и поддерживающей множественный выбор, мне нужен одиночный выбор и открытый лист при двойном щелчке по строке, возможно ли это? также как мне получить выбранный объект элемента?

спасибо 🙏

3 ответа

Решение

Вы должны изменить Set<Value.ID> для Value.ID для выбора только одной строки и сделайте TapGesture в текст.

      @State private var selection = Set<ItemModel.ID>() // <-- Use this for multiple rows selections
      @State private var selection : ItemModel.ID? // <--- Use this for only one row selection
      struct ContentView: View {
    
    @State private var items: [ItemModel] = Array(0...100).map { ItemModel(id: $0, title: "item \($0)", age: $0) }
    //@State private var selection = Set<ItemModel.ID>() <-- Use this for multiple rows selections
    @State private var selection : ItemModel.ID? // <--- Use this for only one row selection
    @State private var sorting = [KeyPathComparator(\ItemModel.age)]
    @State private var showRow = false
    
    var editRow: some View {
        VStack {
            Text(items[selection!].title)
                .font(.title)
            Text("Selected: \(selection.debugDescription)")
             Button("Dismiss") {
                showRow.toggle()
             }.padding()
        }
        .frame(minWidth:400, minHeight: 400)
    }
    
    var body: some View {
        VStack {
            Table(items, selection: $selection, sortOrder: $sorting) {
                TableColumn("id", value: \.id) {
                    Text("\($0.id)")
                        .onTapGesture(count: 2, perform: {
                            if selection != nil {
                                showRow.toggle()
                            }
                        })
                }
                TableColumn("title") { itemModel in
                    Text(itemModel.title)
                        .onTapGesture(count: 2, perform: {
                            if selection != nil {
                                showRow.toggle()
                            }
                        })
                }
                TableColumn("age", value: \.age) { Text("\($0.age)") }
            }
            .onChange(of: sorting) {
                items.sort(using: $0)
            }
            .font(.caption)
            .frame(width: 960, height: 540)
        }
        .sheet(isPresented: $showRow) {
            editRow
        }
    }
}

Что касается двойного щелчка строки таблицы: Apple представила новый модификатор контекстного меню contextMenu(forSelectionType:menu:primaryAction:) в SwiftUI 4 на WWDC 2022. При этомprimaryActionможет быть предусмотрено, что выполняется, когда пользователь дважды щелкает наTableряд.

      @State private var selection: ItemModel.ID?

var body: some View {
    Table(items, selection: $selection, sortOrder: $sortOrder) {
        TableColumn("id", value: \.id)
        TableColumn("title", value: \.title)
        TableColumn("age", value: \.age)
    }
    .contextMenu(forSelectionType: ItemModel.ID.self) { items in
        // ...
    } primaryAction: { items in
        // This is executed when the row is double clicked
    }
}

Как и Адам, в другом ответе есть ряд проблем с областью выбора и временем отклика.

Вы должны установить var selection как ItemModel.ID?но вы также должны обрабатывать действия щелчка по-разному.

Важно отметить, что это будет работать только с Big Sur.

То, как я обрабатываю различные действия для одиночных и двойных щелчков, таково:

      .gesture(TapGesture(count: 2).onEnded {
    print("double clicked")
})
.simultaneousGesture(TapGesture().onEnded {
    print("single clicked")
})

Для вашего примера:

      struct ContentView: View {
    
    @State private var items: [ItemModel] = Array(0...100).map { ItemModel(id: $0, title: "item \($0)", age: $0) }
    @State private var selection = ItemModel.ID?
    @State private var sorting = [KeyPathComparator(\ItemModel.age)]
    @State private var isShowingSheet: Bool = false
    
    var body: some View {
        Table(items, selection: $selection, sortOrder: $sorting) {
            TableColumn("id", value: \.id) {
                Text("\($0.id)").gesture(TapGesture(count: 2).onEnded {
                    self.
                }).simultaneousGesture(TapGesture().onEnded {
                    self.selection = $0.id
                })
            }
            TableColumn("title", value: \.title)
            TableColumn("age", value: \.age) { Text("\($0.age)") }
        }
        .onChange(of: sorting) {
            items.sort(using: $0)
        }
        .font(.caption)
        .frame(width: 960, height: 540).sheet(isPresented: self.$isShowingSheet) {
            Button("Close Sheet") { self.isShowingSheet = false } // <-- You may want to allow click to close sheet.
            Text("Sheet Content Here")
        }
    }
}

Если вы хотите разрешить одиночный и двойной щелчок по всей строке, вам нужно, чтобы содержимое TableColumn заполнило всю ширину столбца и применило модификаторы к остальному содержимому TableColumn.

Другие вопросы по тегам