macOS 上的 SwiftUI:带有详细视图和多选的列表
Posted
技术标签:
【中文标题】macOS 上的 SwiftUI:带有详细视图和多选的列表【英文标题】:SwiftUI on macOS: list with detail view and multiple selection 【发布时间】:2021-01-20 15:06:12 【问题描述】:TL;DR:
我无法在 macOS 上拥有包含详细视图和多项选择的列表。
更详细:
为了演示我的问题,我制作了一个小示例项目。 UI 如下所示:
这是启动时的“应用程序”,顶部有一个列表,下面有一个详细表示。因为我使用的是列表的初始化程序init(_:selection:rowContent:)
,其中selection
根据Apple 的文档是Binding<SelectionValue?>?
类型,所以我可以免费使用键盘箭头键选择项目。
这是完整的代码:
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<Set<SelectionValue>>?
。为了能够获得详细视图,我只是对
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)
现在的问题是我无法再选择行中的项目,无论是通过单击还是通过箭头键。这是我遇到的限制还是我“持有错误”?
【问题讨论】:
【参考方案1】:使用按钮并将其插入集合中。键盘选择也适用于 shift +(向上/向下箭头)
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 中它永远不会追加到设置需要初始化。
@Published var selectedItems: Set<Item> = []
【讨论】:
这是一个想法。您可以为添加删除添加自己的逻辑。 它甚至比这简单得多——但你绝对把我推向了正确的方向,对此我更加感激!我的错误是使集合成为可选的,一旦我删除了一个以空集合开头的集合,它就会按预期工作。 @ASSeeger 只需提供空白默认值即可。因为在 nil 中它永远不会追加到 set need init。【参考方案2】:实际上我的错误非常愚蠢——将selectedItems
-set 设为可选会阻止列表正常工作。向@Raja Kishan 致敬,他的提议将我推向了正确的方向。
这是完整的工作代码:
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 selectedItems = Set<Item>()
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.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)
【讨论】:
以上是关于macOS 上的 SwiftUI:带有详细视图和多选的列表的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI:在 macOS NavigationView 中关闭视图
使用 SwiftUI 的 macOS 应用程序中的导航视图不稳定