SwiftUI 是一种非常简单的创新方法,可以利用 Swift 的强大能力在所有苹果设备平台上构建用户界面。通过 SwiftUI,开发者仅使用一组工具和 API 就能为所有苹果设备构建用户界面。SwiftUI 使用易于阅读和编写的声明式 Swift 语法,可与新的 Xcode 设计工具无缝协作,使你的代码和设计完美同步。SwiftUI 自动支持动态类型、黑暗模式、本地化和可访问性,你的 SwiftUI 代码将成为你写过的最强大的 UI 代码。
基础结构
SwiftUI的视图文件包含两个结构体(Struct) 第一个结构体遵循View
协议,描述视图的内容和布局。
第二个结构体遵循PreviewProvider
协议, 它声明为第一个视图的预览视图。
1 | struct ContentView: View { |
Canvas画布预览
Editor
–Editor and Canvas
或者使用快捷键Command
+ Option
+ Enter
可以打开Canvas
, 点击Canvas
上的Resume
可以预览SwiftUI界面。也可以使用快捷键Command
+ Option
+ P
快速预览。
Inspect
当我们需要修改控件的属性时, 可以使用代码来修改, 也可以在Inspect
中修改, 任一位置修改后预览以及代码编辑器中都会同步修改, 同时预览中也会更新内容的变化。
在预览视图中, 按下Command
键的同时点击控件/类名, 然后选择Inspect
, 在弹出层显示所有可定制的视图属性, 选中的控件不同, 可以定制的属性集合也不相同。
也可以按下Control
+ Option
, 然后鼠标点击控件/类名, 弹出Inspect
窗口。
HStack和VStack
HStack
可以使控件水平布局, VStack
可以使控件垂直布局。默认情况下HStack
和VStack
会把内部的视图在自己的主轴上居中对齐。
Spacer
Spacer
是一个可以伸缩的空白控件, 它负责占用其他控件布局完成后剩下的所有空间。
padding()
使用padding()
可以修改内容视图整体的内边距。
clipShape(Circle())
clipShape(Circle())
给视图添加剪切效果, Circle
是一个圆形的, 当然也可以使用其他形状。
overlay
.overlay(Circle().stroke(Color.white, lineWidth: 4))
可以给视图添加一个白色的边框。
shadow
.shadow(radius: 10)
可以给视图添加一个半径为10的阴影。
UIKit视图和SwiftUI视图混合使用
如果要在SwiftUI中使用UIView及其子类, 需要把这些UIView包裹在一个遵循UIViewRepresentable
协议的SwiftUI视图中, SwiftUI中包含了适配WatchKit
和AppKit
的类似协议。
1 | import SwiftUI |
点击Live Preview
(实时预览)按钮, 可能还需要点击Try Again
或Resume
按钮来激活模式的切换。
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.top)
可以使视图在布局时忽略顶部的安全区域边距。
修改预览的大小或设备
1 | LandmarkRow(landmark: landmarkData[0]) |
List
List
可以展示列表视图, 列表的远可以是静态的, 也可以是动态生成的, 也可以是混合动态静态的视图。
静态数据
1 | List { |
动态数据要配合可辨别的数据类型使用, 想让数据变为可识别的数据类型有两种方法:
- 1、传入一个
keypath
指定数据中哪一个字段用来唯一识别这个数据元素。当元素是简单数据类型时, 可以使用\.self
作为keypath
。
1 | struct LandmarkList: View { |
- 2、让数据遵循
Identifiable
协议
1 | struct Landmark: Hashable, Codable { |
- 3、也可以使用ForEachc创建, 和前面一样, 要么数据遵循
Identifiable
协议, 要么使用keypath
来标识唯一数据。
1 | List { |
添加导航栏
把视图嵌套进一个NavigationView
视图中, 就可以显示导航栏了。使用.navigationTitle("Landmark")
修改导航栏标题。
1 | //iOS 13 |
等价于
1 | // iOS 14.0 |
1 | struct LandmarkList: View { |
使用NavigationLink
跳转页面, 并使用destination
指定跳转的页面。
1 | struct LandmarkList: View { |
设置预览设备
使用.previewDevice(PreviewDevice(rawValue: "iPhone X"))
可以设置调试设备。
使用.previewDisplayName(value)
来给预览设备添加设备标签。
1 | struct LandmarkDetail_Previews: PreviewProvider { |
显示系统图片
1 | Image(systemName: "star.fill") |
@State、@ObservedObject和@EnvironmentObject
状态(@State)是一个值或者一个值的集合, 会随着时间而改变, 同时会影响视图的内容、行为或布局。在属性前面加上@State
修饰词就是给视图添加了一个状态值。@State
一般用于单一视图中。
1 | struct LandmarkList: View { |
遵循ObservableObject
协议的类可以使用SwiftUI的@Published
属性包装器来自动发布属性的变化, 以便使用该类的实例的任何视图都能够自动重新调用body
属性, 保持界面与数据的一致。不过有时候需要更多的控制, SwiftUI对此的解决方式是使用objectWillChange
手动触发。
1 | class DelayedUpdater: ObservableObject { |
SwiftUI的环境可以让我们从外部源中获取值, 这对于读取Core Data
上下文和视图的presentation mode
来说很有用。@EnvironmentObject
可以把一个对象注入环境, 以便任何子视图都可以自动获取该对象的访问能力。要使用@EnvironmentObject
也需要对象遵循ObservableObject
协议以及@Published
修饰词。
1 | class User: ObservableObject { |
@EnvironmentObject
会在环境中自动查找一个User
实例, 并且把找到的结果放进user
属性。注意: 如果环境中找不到User实例, 你的应用会崩溃使用.environmentObject(User())
修改器绑定数据到视图的环境变量中。下面的两种方式的写法都可以。
1 | struct ContentView: View { |
Toggle
Toggle视图可以binding关系(状态引用)切换状态, 使用$
前缀来获得一个状态变量或者属性的绑定关系。
1 | struct LandmarkList: View { |
使用可观察对象来存储数据
可观察对象observalble object
是一种可以绑定到具体SwifUI视图环境中的数据对象。
SwiftUI`可以察觉它影响视图展示的任何变化,并在这种变化发生后及时更新对应视图的展示内容。
- 声明一个遵循
ObservableObject
协议的数据类型,ObservableObject
来自于响应式框架Combine
, SwiftUI可以订阅可观察对象, 并在数据发生改变时更新视图的内容。
1 | import Foundation |
- 添加存储属性并赋初始值。然后使用
@Published
属性修饰词修饰属性。
1 | import Foundation |