如何在SwiftUI中制作一个层次结构的侧栏,其中的子元素与父元素的类型不同?

oknwwptz  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(137)

我正在尝试使用SwiftUI制作一个类似于macOS Mail应用的分层侧栏,其中有父元素,如“All Sent”,然后是子元素,如单个邮箱,与典型的列表标题样式不同,父元素本身是可选的。Example of hiarchical sidebar, from the macOS mail app
我四处寻找解决方案,我能找到的唯一解决方案是父元素和子元素使用相同的swift类型,但我需要适用于不同类型的解决方案,例如,邮件服务器列表,它将文件夹列表作为子元素。

struct MailServer {
  let id: UUID
  let name: String
  let folders: [MailServerFolder] = []
}

struct MailServerFolder {
  let id: UUID
  let name: String
  let items: [Message]
}

struct TestView: View {
  var body: some View {
    List(servers) { server in
      Section(content: {
            ForEach(server.folders) { folder in
                Text(channel.name)
            }
        }, header: {
            HStack {
                Text(server.name)
            }
        })
    }
  }
}

请让我知道是否有办法在SwiftUI中实现这一点,或者是否需要基于AppKit的解决方案。

q3qa4bjr

q3qa4bjr1#

感谢user 1046037和Joakim Danielson的帮助!根据他们的建议,我选择了这个解决方案,效果很好

struct ServerListView: View {
    @EnvironmentObject var store: Store
    @FetchRequest(
            entity: ServerEntry.entity(),
            sortDescriptors: []
    ) var serverEntries: FetchedResults<ServerEntry>
    
    var body: some View {
        List {
            OutlineGroup(Array(serverEntries) as [ServerEntry], id: \.id, children: \.children) { entry in
                Text(entry.title)
            }
        }
    }
}

protocol ListEntry: Identifiable {
    var id: ObjectIdentifier { get }
    var title: String { get }
    var children: [any ListEntry]? { get }
}

extension ServerEntry: ListEntry {
    var title: String {
        return self.name ?? ""
    }
    
    var children: [any ListEntry]? {
        return self.folders?.allObjects as! [FolderEntry]
    }
}

extension FolderEntry: ListEntry {
    var title: String {
        return self.name ?? ""
    }
    
    var children: [any ListEntry]? {
        return nil
    }
}

相关问题