代码之家  ›  专栏  ›  技术社区  ›  superpuccio Kasra

可选@ViewBuilder闭包

  •  0
  • superpuccio Kasra  · 技术社区  · 6 年前

    在SwiftUI中是否可以有一个可选的 @ViewBuilder 关闭?例如,假设我要开发一个自定义视图,它采用两个视图生成器闭包,如下所示:

    import SwiftUI
    
    struct TopAndBottomView<Content>: View where Content: View {
        let topContent: () -> Content
        let bottomContent: () -> Content
    
        init(@ViewBuilder topContent: @escaping () -> Content, @ViewBuilder bottomContent: @escaping () -> Content) {
            self.topContent = topContent
            self.bottomContent = bottomContent
        }
    
        var body: some View {
            VStack {
                topContent()
                Spacer()
                bottomContent()
            }
        }
    }
    
    struct TopAndBottomView_Previews: PreviewProvider {
        static var previews: some View {
            TopAndBottomView(topContent: {
                Text("TOP")
            }, bottomContent: {
                Text("BOTTOM")
            })
        }
    }
    

    但我希望底部视图是可选的。我试过:

    struct TopAndBottomView<Content>: View where Content: View {
        let topContent: () -> Content
        let bottomContent: (() -> Content)?
    
        init(@ViewBuilder topContent: @escaping () -> Content, @ViewBuilder bottomContent: (() -> Content)? = nil) {
            self.topContent = topContent
            self.bottomContent = bottomContent
        }
    
        var body: some View {
            VStack {
                topContent()
                Spacer()
                if bottomContent != nil {
                    bottomContent!()
                }
            }
        }
    }
    

    但我有个错误:

    函数生成器属性“ViewBuilder”只能应用于 函数类型的参数。

    谢谢。

    0 回复  |  直到 6 年前
        1
  •  2
  •   Asperi    6 年前

    考虑到 buildIf 特征 ViewBuilder 以下方法可能允许 视图生成器 在里面 init (这更可取)

    使用Xcode 11.2/iOS 13.2测试和工作

    struct TopAndBottomView<Content>: View where Content: View {
        let topContent: () -> Content
        let bottomContent: () -> Content?
    
        init(@ViewBuilder topContent: @escaping () -> Content, 
             @ViewBuilder bottomContent: @escaping () -> Content? = { nil }) {
            self.topContent = topContent
            self.bottomContent = bottomContent
        }
    
        var body: some View {
            VStack {
                topContent()
                Spacer()
                bottomContent()
            }
        }
    }
    

    所以像这个一样

    struct TopAndBottomView_Previews: PreviewProvider {
        static var previews: some View {
            TopAndBottomView(topContent: {
                Text("TOP")
            }, bottomContent: {
                Text("BOTTOM")
            })
        }
    }
    

    还有这个

    struct TopAndBottomView_Previews: PreviewProvider {
        static var previews: some View {
            TopAndBottomView(topContent: {
                Text("TOP")
            })
        }
    }
    
        2
  •  0
  •   Mamaessen    6 年前

    似乎您不需要在初始值设定项中使用@ViewBuilder,这样就可以:

    struct TopAndBottomView<Content>: View where Content: View {
        let topContent: () -> Content
        let bottomContent: (() -> Content)?
    
        init(@ViewBuilder topContent: @escaping () -> Content, bottomContent: (() -> Content)?) {
            self.topContent = topContent
            self.bottomContent = bottomContent
        }
    
        var body: some View {
            VStack {
                topContent()
                Spacer()
    
                if bottomContent != nil {
                    bottomContent!()
                }
            }
        }
    }