SwiftUI 是苹果在 2019 年推出的声明式 UI 框架。随着 iOS 生态发展,iOS 13 以下系统设备占比已经很低(全部 iPhone 中仅 8%,最近4年的 iPhone 仅 2%),SwiftUI 已经可以作为新项目的首选框架。

重点:

  • 视图本质:值类型而非对象,不可变,用于描述界面状态
  • 修饰器机制:每个修饰器创建新的视图包装器,调用顺序影响最终效果
  • 布局原理:自上而下的布局流程,父视图分配空间,子视图决定尺寸
  • 更新机制:通过状态属性触发视图树重新计算

1.SwiftUI和UIKit的区别:

UIKit 创建的 view 或 view controller 是长时间存在的 UIView 和 UIViewController 实例,通过修改属性来改变屏幕显示内容。SwiftUI 中的 view 是符合 View 协议的短时间存在的值,这些值描述了屏幕上应该显示的内容。view 值是暂时的,可以随时被重新创建。

下图代码中,点击按钮改变 counter 值后,SwiftUI 重新计算这些 view 值,并更新屏幕显示内容:

2.修饰器(modifier,ModifiedContent类型值)

SwiftUI 从最外层的 view 开始布局。ContentView 是 view 层级的根节点,布局系统为它提供整个屏幕边界进行布局。ContentView 把相同的尺寸提供给 VStack 让它自行布局。VStack 根据子 view 的数量,将可用的竖直空间进行划分,并提供给每个 view,如果 view 下面有修饰器,则会依据修饰器中包裹的条件文本标签来判断如何分配空间。

Button 下方的 .padding() 是一个修饰器,将 Text 包装为 ModifiedContent 类型的值,这个值包含有关如何设置 padding 填充的信息。增加 .background 会把现有值包装起来创建一个新的 ModifiedContent 值,添加背景色信息。

修饰器的顺序很重要,下面两张图展示了修饰器顺序不同产生的不同效果。第一张图实际运行时没有蓝框,这个框是 Xcode 标注给开发者看的 view 范围。

3.view更新

更改 @State、@ObservedObject 或 @StateObject 标记的属性值,会触发 view 树的重新计算。

第一张截图中的 counter 值改变后,SwiftUI 再次访问 content view 的 body 属性,获取对应新状态的 view 树。view 树的类型在编译时就已经固定,无法改变,能改变的是它的值,例如 Text 显示的文字,以及采用 if 语句的哪个分支。

更改状态属性是 SwiftUI 中唯一的更新 view 的方法,这种处理方式可以避免 UIKit 中 view 和 app 状态不同步的常见错误。