SwiftUI:如何从 OutlineGroup 中获取选择?

Posted

技术标签:

【中文标题】SwiftUI:如何从 OutlineGroup 中获取选择?【英文标题】:SwiftUI: How to get selections from OutlineGroup? 【发布时间】:2020-06-24 01:36:55 【问题描述】:

OutlineGroup 类似于 NSOutlineViewNSOutlineView支持单/多节点选择,可以通过NSOutlineView查询获得。虽然在NSOutlineView获得选择是 O(n),但如果视图跟踪选择并在适当的界面中提供它们,这可以优化到 O(1)。

如何获取OutlineGroup的选择?特别是对于多节点选择。我检查了the manual entry,但找不到任何关于选择的提及。我在这里错过了什么?

【问题讨论】:

从另一个问题回答。 ***.com/a/63786164/246776 【参考方案1】:

文档看起来并没有完全完成。在 Xcode 12 中使用直接 SwiftUI 自动生成的接口来查找更新。

特别是问OutlineGroup 有几个带有selection 参数的构造函数,如下所示:

/// Creates a hierarchical list that computes its rows on demand from an
/// underlying collection of identifiable data, optionally allowing users to
/// select multiple rows.
///
/// - Parameters:
///   - data: The identifiable data for computing the list.
///   - selection: A binding to a set that identifies selected rows.
///   - rowContent: A view builder that creates the view for a single row of
///     the list.
@available(ios 14.0, OSX 10.16, *)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
public init<Data, RowContent>(_ data: Data, children: KeyPath<Data.Element, Data?>, 
    selection: Binding<Set<SelectionValue>>?, @ViewBuilder rowContent: @escaping (Data.Element) -> RowContent) where Content == OutlineGroup<Data, Data.Element.ID, HStack<RowContent>, HStack<RowContent>, DisclosureGroup<HStack<RowContent>, OutlineSubgroupChildren>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable

【讨论】:

我在自动生成的界面上找不到这个。你在 macOS 11(测试版)上检查过这个吗?我还在使用 macOS 10.x 看来OutlineGroup 需要是List 的内容。 @Eonil,不,我已经在 macOS 10.15.5 上安装了 Xcode 12b【参考方案2】:

您需要为没有子项的项目放置NavigationLink/Button

这是基于 Apple 源代码的外观。

var body: some View 
    OutlineGroup(data, children: \.children)  item in
        Group 
            if item.children == nil 
                NavigationLink(
                    destination: Text("\(item.name)"),
                    label: 
                        Text ("\(item.description)")
                    )
             else 
                Text ("\(item.description)")
            
        
    

数据来自 Apple example。有时链接会被破坏。所以,这里是源代码:

struct FileItem: Hashable, Identifiable, CustomStringConvertible 
    var id: Self  self 
    var name: String
    var children: [FileItem]? = nil
    var description: String 
        switch (children) 
        case nil:
            return "? \(name)"
        case .some(let children):
            return children.count > 0 ? "? \(name)" : "? \(name)"
        
    


let data =
    FileItem(name: "users", children:
                [FileItem(name: "user1234", children:
                            [FileItem(name:"Photos", children:
                                        [FileItem(name: "photo001.jpg"),
                                         FileItem(name: "photo002.jpg")]),
                             FileItem(name:"Movies", children:
                                        [FileItem(name: "movie001.mp4")]),
                             FileItem(name:"Documents", children: [])
                            ]),
                 FileItem(name: "newuser", children:
                            [FileItem (name: "Documents", children: [])
                            ])
                ])

【讨论】:

这如何使大纲组可选择? 没有子项的项目被包裹在 NaviationLink 中。 有人有解决这个问题的办法吗?请在此处发布。【参考方案3】:

这是代码。

import SwiftUI

struct ContentView: View 
    @State var selection = Set<FileItem.ID>()
    var body: some View 
        NavigationView 
            VStack 
                List(selection: $selection) 
                    OutlineGroup(data, children: \.children)  item in
                        Text("\(item.description)")
                    
                    .onTapGesture 
                        print(selection)
                    
                
                .listStyle(InsetGroupedListStyle())
                .navigationTitle("Files")
                //.toolbar  EditButton() 
                .environment(\.editMode, .constant(.active))
                .onTapGesture 
                    // Walkaround: try how it works without `asyncAfter()`
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.05, execute: 
                        print(selection)
                    )
                
                Text("\(selection.count) selections")
            
        
        
    


// Sample data:

struct FileItem: Hashable, Identifiable, CustomStringConvertible 
    var id: Self  self 
    var name: String
    var header: String?
    var children: [FileItem]? = nil
    var description: String 
        switch children 
        case nil:
            return "? \(name)"
        case .some(let children):
            return children.isEmpty ? "? \(name)" : "? \(name)"
        
    


let data =
  FileItem(name: "users", children:
    [FileItem(name: "user1234", children:
                [FileItem(name: "Photos", header: "Header 1", children:
        [FileItem(name: "photo001.jpg", header: "Header 2"),
         FileItem(name: "photo002.jpg")]),
       FileItem(name: "Movies", children:
         [FileItem(name: "movie001.mp4")]),
          FileItem(name: "Documents", children: [])
      ]),
     FileItem(name: "newuser", children:
       [FileItem(name: "Documents", children: [])
       ])
    ])

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

【讨论】:

以上是关于SwiftUI:如何从 OutlineGroup 中获取选择?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SwiftUI 从文本中提取 Hashtags?

如何从 SwiftUI 视图转到 UIKit TabViewController?

如何从内部的 SwiftUI 视图返回到 UIKit?

如何知道应用程序是不是从 SwiftUI 中的后台删除?

如何从 SwiftUI 中的函数返回按钮?

如何从swiftui视图调用uikit viewcontroller方法