SwiftUI

SwiftUI 布局系统

SwiftUI 使用灵活的盒子布局系统,SwiftUI 的布局主要步骤如下:

1. 父 View 为子 View 建议一个大小。
2. 根据建议大小, 子View 确定自己的大小。
3. 父 View将子View 放在适当的位置。

案例1

// 案列代码1
struct ContentView: View {
      var body: some View {
      Text("Hello, SwiftUI!") .background(Color.orange)
 }
 }

此时显示的内容为橘色背景围绕着文本“Hello, SwiftUI!”,它只用了一个 “足够的空间” 来适应显示的内容。那么现在的问题是:ContentView 到底有多大? 其实 ContentView 的大小是body 里面所呈现的内容的大小,也就是说 ContentView 没有自己的大小,而是调整自己的大小以适应内容需要的大小,这就是 SwiftUI 中所谓的布局无关( layout neutral )。


布局无关

• 如果一个 View 布局无关,则可以绘制任何大小的 View。
• 布局无关的 View 会通过询问其子 View 需要多少空间并使用相同的值来确定所需的空间。
• 如果 View 的层次结构是完全布局无关的,那么它将自动占用所有可用的空间。 例如,
形状和颜色的布局是中立的,如果 View 仅包含一个颜色或一种形状,那么它会自动填充
整个屏幕( safeArea 范围内)。

布局过程

1. SwiftUI 布局系统首先询问ContentView:你拥有整个屏幕大小, 这次布局你需要多大空 间? (父View建议一个大小)
2. ContentView 布局无关, 所以它询问 background:你可以拥有整个屏幕大小 ,那你需要多大空间?(父View建议一个大小)
3. background 也布局无关, 所以它询问Text:你可以拥有整个屏幕大小, 那你需要多大空间?(父View建议一个大小)
4. Text 里面有文本内容, 字体默认, 所以它向 background反馈:只需要 x* y的大小即可, 而不需要整个屏幕大小 。(子View确定自己的大小)
5. background 向 ContentView 反馈: 需要 x* y的大小。
6. ContentView 向 SwiftUI布局系统反馈: 需要 x* y的大小。
7. SwiftUI 布局系统知道了 ContentView 需要的空间大小后发现屏幕剩余很多空间,于是
以默认方式把 ContentView 放在屏幕的在中间。 (父 View 将子 View 放在适当的位置)

总结

•在示例中, ContentView 中的顶级 View 是background, Text 成为 background 的 子 View 。
•当涉及到 View 及其修饰符时, SwiftUI 布局系统会按照从下至上的顺序开始布局。

案例2

// 案列代码2
// 此时显示的内容是在案例一中的基础上在文本周围多了四个方向的 20 填充。
struct ContentView: View {
      var body: some View {
      Text("Hello, SwiftUI!") .padding(20).background(Color.orange)
 }
 }

布局过程

1. SwiftUI 布局系统首先询问 ContentView:你拥有整个屏幕大小,这次布局你需要多大空 间? (父View建议一个大小)
2. ContentView 布局无关,所以它询问 background:你可以拥有整个屏幕大小,那你需要多大空间?(父View建议一个大小)
3. background 也布局无关,所以它询问 padding:你可以拥有整个屏幕大小,那你需要多大空间?(父View建议一个大小)
4. padding 有值 20,所以它需要每个方向填充 20,然后它询问 Text:你可以拥有整个屏 幕去掉四周各 20后的大小,那你需要多大空间?(子View确定自己的大小)
5. Text 里面有文本内容,字体默认,所以它向 padding 反馈:只需要 x * y 的大小即可,而不需要整个屏幕大小 。(子View确定自己的大小)
6. padding 向 background 反馈:需要 x * y 的大小,然后在四周各填充 20。
7. background 向 ContentView 反馈:需要 x * y 的大小,然后在四周各 填充 20。
8. ContentView 向 SwiftUI布局系统反馈:需要 x * y  的大小,然后在四周 各填充 20。
9. SwiftUI 布局系统知道了 ContentView 需要的空间大小后发现屏幕剩余很多空间,
   于是以默认方式把 ContentView 放在屏幕的在中间。 (父 View 将子View 放在适当位置)