【问题标题】:Passing multiple subviews to a view in SwiftUI将多个子视图传递给 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")
       }
     }
}

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

【问题讨论】:

    标签: swiftui


    【解决方案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,我想它可能对你有用。
      • 甜蜜!我真的很喜欢这个解决方案!谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-24
      • 2021-06-21
      相关资源
      最近更新 更多