微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

macOS 上的 SwiftUI:具有详细视图和多项选择的列表

如何解决macOS 上的 SwiftUI:具有详细视图和多项选择的列表

TL;DR:

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

更详细:

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

enter image description here

这是启动时的“应用程序”,顶部是列表,下面是详细表示。因为我正在使用列表的初始化程序 init(_:selection:rowContent:),其中 selection 根据 Apple 的文档属于 Binding<SelectionValue?>? 类型,所以我可以免费使用键盘箭头键选择项目。

enter image description here

完整代码如下:

import SwiftUI

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

class viewmodel: ObservableObject {
    @Published var items = [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 的类型为 { {1}}。为了能够有详细的视图,我只是对

做了一些小改动

Binding<Set<SelectionValue>>?

viewmodel

class viewmodel: ObservableObject { @Published var items = [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

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

解决方法

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

class ViewModel: ObservableObject {
    @Published var items = [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 需要初始化。

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

实际上我的错误非常愚蠢——将 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()]
    @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,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)
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。