【问题标题】:How to interpret VStack{ .. } from SwiftUI's official tutorial code? [duplicate]如何从 SwiftUI 的官方教程代码中解释 VStack{ .. }? [复制]
【发布时间】:2020-02-23 12:36:02
【问题描述】:

在下面的代码中,我知道

  1. body 是一个计算属性,它只有一个 get 部分。
  2. return 被省略 VStack

但是 Vstack 之后的 { .. } 是什么?这是初始化还是闭包? 以及 {} 里面的内容,我认为没有任何回报。

struct ContentView: View {
    var body: some View {
        VStack {
            MapView()
                .frame(height: 300)

            CircleImage()
                .offset(y: -130)
                .padding(.bottom, -130)

            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                HStack(alignment: .top) {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding()

            Spacer()
        }
    }
}

【问题讨论】:

  • return 计算属性的关键字现在可以在 swift 5.1 中省略

标签: swift swiftui


【解决方案1】:

如果您查看VStack.init 的文档,您会发现它接受的最后一个参数确实是一个闭包。这里的神奇之处在于闭包标有@ViewBuilder

@ViewBuilderfunction builder 的一种。这个想法是你传入一个包含一堆表达式的闭包,然后函数构建器会将这些表达式组合成一个值。这有点像返回一个数组,但可以说是更好看的语法。 (虽然它不是真正的数组。闭包的返回类型由函数构建器决定。)

在您的代码中,您将返回一个包含 4 个视图的“数组”。

  1. MapView
  2. CircleImage
  3. 另一个VStack
  4. Spacer

这些将被传递给ViewBuilder,并将它们组合成一个View 对象。

如果您想知道在每个视图结束时调用的方法在做什么,它们只是返回对调用它们的对象的轻微修改的方法。例如padding 返回相同的视图,但应用了一些填充。

【讨论】:

  • 非常感谢,这说明了一切。
【解决方案2】:

VStack 语法之所以成为可能,要归功于 Swift 5.1 中称为 Function Builder 的新功能。
如果没有函数构建器,代码将如下所示:

var body: some View {
    var builder = VStackBuilder()
    builder.add(Image(uiImage: image))
    builder.add(Text(title))
    builder.add(Text(subtitle))
    return builder.build()
}

【讨论】:

  • 非常感谢,这说明了一切。
【解决方案3】:

当你查看VStack初始化器的签名时:

public init(alignment: HorizontalAlignment = .center, spacing: CGFloat? = nil, @ViewBuilder content: () -> Content)

您可以看到它需要 3 个参数,前两个具有默认值,因此可以省略(如您的示例中所示)。最后一个是ViewBuilder,没有默认值,所以需要提供。

当您查看 ViewBuilder 的定义时,它需要 0 到 10 个视图:

static func buildBlock() -> EmptyView
static func buildBlock<Content>(Content) -> Content
static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)>
/....
static func buildBlock<C0, C1, C2, C3, C4, C5, C6, C7, C8, C9>(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9) -> TupleView<(C0, C1, C2, C3, C4, C5, C6, C7, C8, C9)>

长话短说,您在 { .. } 之间看到的是 ViewBuilder,它是一个闭包,是初始化程序的一部分。

【讨论】:

  • 非常感谢,这说明了一切。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
相关资源
最近更新 更多