macOS 上的 SwiftUI:具有详细视图和多项选择的列表 [英] SwiftUI on macOS: list with detail view and multiple selection

查看:96
本文介绍了macOS 上的 SwiftUI:具有详细视图和多项选择的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL;DR:

我无法在 macOS 上创建包含详细信息视图和多项选择的列表.

I cannot have a list with a detail view and multiple selections on macOS.

更详细:

为了演示我的问题,我做了一个小示例项目.用户界面如下所示:

For demonstration purposes of my issue, I made a small example project. The UI looks as follows:

这是应用程序"启动时,顶部有一个列表,下面有一个详细的表示.因为我使用的是列表的初始化程序 init(_:selection:rowContent:),其中 selection 的类型是 Binding?根据Apple的文档,我可以免费使用键盘箭头键选择项目.

This is the "app" when launched, with a list on top and a detail representation below. Because I am using the List's initialiser init(_:selection:rowContent:), where selection is of type Binding<SelectionValue?>? according to Apple's documentation, I get selecting items with the keyboard arrow keys for free.

完整代码如下:

import SwiftUI

@main
struct UseCurorsInLisstApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(ViewModel())
        }
    }
}

class ViewModel: ObservableObject {
    @Published var items = [Item(), Item(), Item(), Item(), Item()]
    @Published var selectedItem: Item? = nil
}

struct Item: Identifiable, Hashable {
    let id = UUID()
}

struct ContentView: View {
    @EnvironmentObject var vm: ViewModel
    
    var body: some View {
        VStack {
            
            List(vm.items, id: \.self, selection: $vm.selectedItem) { item in
                VStack {
                    Text("Item \(item.id.uuidString)")
                    Divider()
                }
            }
            
            Divider()
            
            Group {
                if let item = vm.selectedItem {
                    Text("Detail item \(item.id.uuidString)")
                } else {
                    Text("No selection…")
                }
            }
            .frame(minHeight: 200.0, maxHeight: .infinity)
            
        }
    }
}

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

现在,到目前为止已经取得了成功,我认为能够选择多于一行会很有用,所以我仔细研究了 List(_:selection:rowContent:),其中 selection 的类型为 Binding>?.为了能够有详细的视图,我只是对

Now, having had success with this so far, I figured being able to select more than one row would be useful, so I took a closer look into List(_:selection:rowContent:), where selection is of type Binding<Set<SelectionValue>>?. To be able to have a detail view, I just made a few minor changes to

ViewModel:

class ViewModel: ObservableObject {
    @Published var items = [Item(), Item(), Item(), Item(), Item()]
    @Published var selectedItem: Item? = nil
    
    @Published var selectedItems: Set<Item>? = nil {
        didSet {
            if selectedItems?.count == 1, let item = selectedItems?.first {
                selectedItem = item
            }
        }
    }
}

ContentView:

struct ContentView: View {
    @EnvironmentObject var vm: ViewModel
    
    var body: some View {
        VStack {
            
            List(vm.items, id: \.self, selection: $vm.selectedItems) { item in
                VStack {
                    Text("Item \(item.id.uuidString)")
                    Divider()
                }
            }
            
            Divider()
            
            Group {
                if vm.selectedItems?.count == 1, let item = vm.selectedItems?.first {
                    Text("Detail item \(item.id.uuidString)")
                } else {
                    Text("No or multiple selection…")
                }
            }
            .frame(minHeight: 200.0, maxHeight: .infinity)
            
        }
    }
}

现在的问题是我无法再选择行中的项目,无论是通过单击还是通过箭头键.这是我遇到的限制还是我认为它错了"?

The problem now is that I cannot select an item of the row any more, neither by clicking, nor by arrow keys. Is this a limitation I am running into or am I "holding it wrong"?

推荐答案

使用按钮并将其插入到集合中.键盘选择也适用于 shift +(向上/向下箭头)

Use the button and insert it into the set. Keyboard selection also works with shift + (up/down arrow)

class ViewModel: ObservableObject {
    @Published var items = [Item(), Item(), Item(), Item(), Item()]
    @Published var selectedItem: Item? = nil
    
    @Published var selectedItems: Set<Item> = []
}

struct ContentView: View {
    @EnvironmentObject var vm: ViewModel
    
    var body: some View {
        VStack {
            
            List(vm.items, id: \.self, selection: $vm.selectedItems) { item in
                Button {
                    vm.selectedItem = item
                    vm.selectedItems.insert(item)
                } label: {
                    VStack {
                        Text("Item \(item.id.uuidString)")
                        Divider()
                    }
                }
                .buttonStyle(PlainButtonStyle())
            }
            
            Divider()
            
            Group {
                if let item = vm.selectedItem {
                    Text("Detail item \(item.id.uuidString)")
                } else {
                    Text("No or multiple selection…")
                }
            }
            .frame(minHeight: 200.0, maxHeight: .infinity)
            
        }
    }
}

添加删除:

Button {
    vm.selectedItem = item
    if vm.selectedItems.contains(item) {
        vm.selectedItems.remove(item)
    } else {
        vm.selectedItems.insert(item)
    }
}

编辑简单的需要给一个空白的默认值来设置.因为在 nil 中它永远不会追加到 set 需要初始化.

Edit In simple need to give a blank default value to set. because in nil it will never append to set need initialization.

@Published var selectedItems: Set<Item> = [] {

这篇关于macOS 上的 SwiftUI:具有详细视图和多项选择的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆