在 SwiftUI 中构建一个自定义的类 TabView 视图

Posted

技术标签:

【中文标题】在 SwiftUI 中构建一个自定义的类 TabView 视图【英文标题】:Building a custom TabView-like view in SwiftUI 【发布时间】:2019-10-22 22:52:13 【问题描述】:

我一直在尝试为 macOS 构建一个工具栏-tabview 组件,它可以与子视图组成,就像下面的 TabView 一样:

struct ContentView: View     
    var body: some View 
        TabView 
            Text("First View")
                .tabItem 
                    Image(name: "NSUserAccounts")
                    Text("First")
                .tag(0)
            Text("Second View")
                .tabItem 
                    Image(name: "NSUserAccounts")
                    Text("Second")
                .tag(1)
        
    
 

目前我有这样的事情:

struct ToolbarTabView<Content>: NSViewControllerRepresentable where Content: View 

    let content: () -> Content

    init(@ViewBuilder content: @escaping () -> Content) 
        self.content = content
    

    func makeNSViewController(context: NSViewControllerRepresentableContext<ToolbarTabView>) -> NSTabViewController 
        let vc = NSTabViewController()
        vc.tabStyle = .toolbar


        for item in self.content() as! something? 
            let t = NSTabViewItem(viewController: NSHostingController(rootView: item))
            t.image = item.image
            t.label = item.label
            t.identifier = item.identifier
            vc.addTabViewItem(t)
        

        return vc
    

    func updateNSViewController(_ nsViewController: NSTabViewController, context: NSViewControllerRepresentableContext<ToolbarTabView>) 
    

    typealias NSViewControllerType = NSTabViewController



使用 SwiftUI 可以实现这样的事情吗? TabView 内容如何被投射并用于获取 Image 和 Label 信息?

【问题讨论】:

我正在尝试用 NSScrollView 做类似的事情。我试过这样的代码,也试过使用 NSViewRepresentable/NSHostingView。我可以让滚动视图显示正常,但不能显示其内容。你找到解决办法了吗? 好的,我发现我的问题和你的有点不同。但我和你一起玩,找到了答案。我会把它贴在下面:-) 【参考方案1】:

除了将内容传递给您的 ToolbarTabView,您还可以让它接受一个还包含其他值的数组。试试这样的:

struct ToolbarTabView<Content>: NSViewControllerRepresentable where Content: View 

    let tabs: [(imageName: String, label: String, identifier: Int, content: () -> Content)]

    init(tabs: [(imageName: String, label: String, identifier: Int, content: () -> Content)]) 
        self.tabs = tabs
    

    func makeNSViewController(context: NSViewControllerRepresentableContext<ToolbarTabView>) -> NSTabViewController 
        let vc = NSTabViewController()
        vc.tabStyle = .toolbar


        for item in tabs 
            let t = NSTabViewItem(viewController: NSHostingController(rootView: item.content()))
            //t.image = item.image
            t.label = item.label
            t.identifier = item.identifier  // this causes an "unrecognized selector" error, but maybe I'm passing a bad value for this, I'm not sure what it expects
            vc.addTabViewItem(t)
        

        return vc
    

    func updateNSViewController(_ nsViewController: NSTabViewController, context: NSViewControllerRepresentableContext<ToolbarTabView>) 
    

    typealias NSViewControllerType = NSTabViewController




struct ToolbarTabView_Previews: PreviewProvider 
    static var previews: some View 
        ToolbarTabView(tabs: [
            (
                imageName: "My Image",
                label: "tab1",
                identifier: 0,
                content: 
                    Text("testing")
                
            )
        ])
    

【讨论】:

我正在做类似的事情。我看到的问题是您的ToolbarTabView 期望Contenttabs 中的每个元组中都是相同的类型。如果用户想要比单个Text 更复杂的选项卡,我不确定这是否会编译。

以上是关于在 SwiftUI 中构建一个自定义的类 TabView 视图的主要内容,如果未能解决你的问题,请参考以下文章

如何从 webkit swiftUI 中的文本字段中搜索自定义文本

我们如何在 SwiftUI 中制作自定义 GeometryReader?

SwiftUI 自定义 List 不能在 ForEach 中使用 Binding

安装了 FB 应用程序的 SwiftUI 自定义 Facebook 登录

Swift之SwiftUI自定义star rating评分组件

SwiftUI 官方教程