使用@ViewBuilder创建支持多个子视图的视图

时间:2019-06-10 19:21:18

标签: swift swiftui

SwiftUI中的某些视图(例如VStack和HStack)支持将多个视图作为子视图,如下所示:

VStack {
  Text("hello")
  Text("world")
}

根据我的收集,他们使用ViewBuilder使之成为可能,如here所述。

我们如何使用@ViewBuilder创建自己的支持多个子视图的视图?例如,假设我要创建一个Layout视图,该视图可以接受任意子级-

struct Layout : View {
  let content: Some View 

  var body : some View {
    VStack {
      Text("This is a layout")
      content()
    }
  } 
}

有人知道如何在SwiftUI中实现此模式吗?

2 个答案:

答案 0 :(得分:2)

这是一个不执行任何操作的示例视图,仅用于演示如何使用@ViewBuilder

struct Passthrough<Content>: View where Content: View {

    let content: () -> Content

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

    var body: some View {
        content()
    }

}

用法:

Passthrough {
    Text("one")
    Text("two")
    Text("three")
}

答案 1 :(得分:1)

使用VStack的声明,我们需要对内容参数使用@ViewBuilder。它是一个闭包,但不应 @转义如果只需要闭包中的数据,则存储闭包就不好了。我认为是从Apple声明中得出的。

我还认为@inlinable很重要,因为:

  

@inlinable属性将函数的主体导出为a的一部分   模块的接口,使其在优化器可用时   从其他模块引用。   More info here

struct Layout <Content> : View where Content : View {

        var content: Content

        @inlinable public init(@ViewBuilder content: () -> Content) {
            self.content = content()
        }

        var body : some View {
            VStack {
                Text("This is a layout")
                self.content
            }
        } 
    }

要使用它:

Layout {           
            Text("1")
            VStack {
                Text("1")
                Text("2")
            }
        }

UPD: 正如Matteo Pacini所指出的关于@escaping的误导性信息。

我们需要对@escaping视图使用DynamicViewContent@escaping用于Apple的View结构,用于接受集合(数组,范围等)的视图结构。因为ForEach实现了DynamicViewContent-一种视图类型,可从基础数据集中生成视图。 List在其初始值设定项中,ForEach在其内容

 public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, action: @escaping (Data.Element.IdentifiedValue) -> Void, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, Button<HStack<RowContent>>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable