SwiftUI 的主体中是否需要 VStack

6 swiftui

我有以下代码:

  var body: some View {
    VStack {
      contentView
        .padding()
      
      ToolBarView()
        .padding()
    }
  }
Run Code Online (Sandbox Code Playgroud)

我注意到,如果我删除VStack,代码仍然有效。这很奇怪。它们相等吗?这里隐式使用了吗VStack?如果我保留这个VStack,是否意味着 SwiftUI 将生成重复的嵌套VStack

编辑:

contentView

  var contentView: some View {
    let state = stateObservable.state
    if state.isResultPage {
      return AnyView(ResultContentView())
    } else {
      return AnyView(JokeContentView())
    }
  }
Run Code Online (Sandbox Code Playgroud)

rob*_*off 10

为了避免需要定义 a ToolBarView,我将使用此示例而不是您的示例:

\n
struct MyView: View {\n    var body: some View {\n        Text("first")\n        Text("second")\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

那么,返回的实际类型是什么MyView().body?让我们问斯威夫特:

\n
; xcrun swift\nWelcome to Swift version 5.5.2-dev.\nType :help for assistance.\n  1> import SwiftUI\n  2> struct MyView: View { \n  3.     var body: some View { \n  4.         Text("first") \n  5.         Text("second") \n  6.     } \n  7. }\n  8> print(type(of: MyView().body))\nTupleView<(Text, Text)>\n
Run Code Online (Sandbox Code Playgroud)\n

它是TupleView<(Text, Text)>。那么 a 到底是什么TupleView?文档说它是

\n
\n

从视图值的快速元组创建的视图。

\n
\n

\xe2\x80\xa6这并没有真正解释太多。请允许我解释一下TupleView到底是什么。

\n

SwiftUI 用于TupleView表示视图的集合,而不对它们强加任何特定的布局。布局完全由 的容器TupleView(或者在本例中为MyView)决定。如果您总是想要垂直布局,则需要VStack显式使用。如果您希望容器选择布局,请不要使用VStack.

\n

如果我们将 放入MyViewa 中VStack,我们会得到一个垂直布局。

\n
PlaygroundPage.current.setLiveView(VStack {\n    MyView()\n})\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个高于第二个

\n

但如果我们把 放在MyViewan 中HStack,我们就会得到一个水平布局。

\n
PlaygroundPage.current.setLiveView(HStack {\n    MyView()\n})\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个到第二个的左边

\n

或者我们可以MyView在 a 中ControlGroup获得不同的水平布局:

\n
PlaygroundPage.current.setLiveView(ControlGroup {\n    MyView()\n})\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个文本位于第二个文本的左侧,它们之间有分隔线,两个文本均变暗

\n

如果我们把MyViewa 放在里面ZStackTexts 就会被覆盖。

\n
PlaygroundPage.current.setLiveView(ZStack {\n    MyView()\n})\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个和第二个重叠

\n

如果我们把MyViewa 放在里面GeometryReaderTexts 就会再次被覆盖。

\n
PlaygroundPage.current.setLiveView(GeometryReader { proxy in\n    MyView()\n}.frame(width: 100, height: 100))\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个和第二个重叠在白色 100 点正方形的左上角

\n

如果我们用作MyViewa 的主体PreviewProvider,那么我们会得到两个完全独立的预览。

\n
struct MyView_Previews: PreviewProvider {\n    static var previews: some View {\n        MyView()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

结果:

\n

第一个的预览高于第二个的预览

\n