将多个子视图传递给 SwiftUI 中的视图

Posted

技术标签:

【中文标题】将多个子视图传递给 SwiftUI 中的视图【英文标题】:Passing multiple subviews to a view in SwiftUI 【发布时间】:2020-11-23 21:19:27 【问题描述】:

我创建了一个 Swift 包,它从传递给它的内容数组创建多个 PageTabView:

import SwiftUI

public struct WhatsNewView<Content: View>: View 
    
    let content: [Content]
    
    public init(content: [Content])
        self.content = content
    
        
    public var body: some View 
        TabView 
            ForEach(0..<content.count, id: \.self)  pageNum in
                WhatsNewPage(content: content[pageNum], pageNum: pageNum + 1, totalPages: content.count)
            
        
        .background(Color.white)
        .ignoresSafeArea()
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    

当我调用它时,我想传入任何类型的简单或复杂视图来填充每个页面。现在,我可以像这样传入一组简单的文本视图:

import SwiftUI
import WhatsNew

@main
struct mFood_Vendor: App 
    @State var showWhatsNew = false
    let whatsNew = WhatsNew()

    var page1 = Text("Hello World")

    var page2 = Text("Goodbye World")

    var body: some Scene 
        WindowGroup 
            ContentView()
            .fullScreenCover(isPresented: $showWhatsNew, content: 
                let content = [page1, page2]
                WhatsNewView(content: content)
            )
            .onAppear(perform: 
                whatsNew.checkForUpdate(showWhatsNew: $showWhatsNew)
            )

        
    

我希望 page1 和 page2 成为人们希望在 What's New 页面上看到的任何内容。但是,如果我将这些变量更改为任何不同的内容,例如文本和图像,我会收到“无法生成表达式诊断”错误。

理想情况下,我希望能够传递以下内容:

struct page1: View 
    var body: some View 
      VStack 
        Text("something")
        Image("plus")
       
     

任何帮助将不胜感激。谢谢!

【问题讨论】:

【参考方案1】:

您可以使用AnyView 来获得您想要的。在这种情况下,您的代码将变为:

public struct WhatsNewView: View 

    let content: [AnyView]

    public init(content: [AnyView])
        self.content = content
    

    public var body: some View 
        TabView 
            ForEach(0..<content.count, id: \.self)  pageNum in
                WhatsNewPage(content: content[pageNum], pageNum: pageNum + 1, totalPages: content.count)
            
        
        .background(Color.white)
        .ignoresSafeArea()
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    

并且,作为使用示例:

struct ContentView: View 
    var body: some View 
        let view1 = AnyView(Text("Hello World"))
        let view2 = AnyView(Image(systemName: "star.fill"))
        return WhatsNewView(content: [view1, view2])
    

编辑:我刚刚发现TabView 可以由TupleView 构建而成。这意味着,根据你的需要,你可以写这样的东西(这很好,因为它不会强迫你的 Swift Package 用户将所有视图包装在 AnyView 中):

import SwiftUI

public struct WhatsNewView<Content: View>: View 
    private let content: Content

    public init(@ViewBuilder contentProvider: () -> Content)
        content = contentProvider()
    

    public var body: some View 
        TabView 
            content
        
        .background(Color.white)
        .ignoresSafeArea()
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    

你可以这样使用它:

struct ContentView: View 
    var body: some View 
        WhatsNewView 
            Text("Hello World")
            Image(systemName: "star.fill")
            Color.red
            VStack 
                Text("Text1")
                Text("Text2")
                Text("Text3")
            
            Button("Tap Me") 
                print("Tapped")
            
            Group 
                Text("Group1")
                Text("Group2")
            
        
    

结果是:

【讨论】:

【参考方案2】:

事实证明,如果我不理会 WhatsNewView,我可以执行以下操作:

struct mFood_Vendor: App 
    @State var showWhatsNew = false
    let whatsNew = WhatsNew()

    var page1: some View 
        VStack (alignment: .leading)
            Text("Here is a list of new features:")
            Text("Hello World")
            Image(systemName: "plus")
        
    

    var page2: some View 
        Text("Goodbye World")
    

    var body: some Scene 
        WindowGroup 
            ContentView()
            .fullScreenCover(isPresented: $showWhatsNew, content: 
                let content = [AnyView(page1), AnyView(page2)]
                WhatsNewView (content: content)
            )
            .onAppear(perform: 
                whatsNew.checkForUpdate(showWhatsNew: $showWhatsNew)
            )

        
    

基本上只是将每个内容页面包装在 AnyView 中。

【讨论】:

看看我的 EDIT,我想它可能对你有用。 甜蜜!我真的很喜欢这个解决方案!谢谢。

以上是关于将多个子视图传递给 SwiftUI 中的视图的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 将数组的元素作为绑定传递给子视图

SwiftUI-将@State变量传递给多个视图麻烦

如何将数据从父模型类传递到 SwiftUI 中的子视图

如何将通用视图传递给 SwiftUI 中的结构

如何将可选视图传递给 SwiftUI 中的另一个视图?

有没有办法在 SwiftUI 中复制手势或处理它们并将它们传递给子视图?