一、SwiftUI介绍
1.1 创建视图
外框效果
1
2
3
4
5
6
|
Image("turtlerock")
.clipShape(Circle())
.overlay {
Circle().stroke(.white, lineWidth: 4)
}
.shadow(radius: 7)
|
地图组件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import SwiftUI
import MapKit
struct MapView: View {
@State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 34.011_286, longitude: -116.166_868),
span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
)
var body: some View {
Map(coordinateRegion: $region)
}
}
|
从文件加载数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import Foundation
var landmarks: [Landmark] = load("landmarkData.json")
func load<T: Decodable>(_ filename: String) -> T {
let data: Data
guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
else {
fatalError("Couldn't find \(filename) in main bundle.")
}
do {
data = try Data(contentsOf: file)
} catch {
fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}
do {
let decoder = JSONDecoder()
return try decoder.decode(T.self, from: data)
} catch {
fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}
|
1.2 构建List和导航
自定义预览
1
2
3
4
5
6
7
8
9
|
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
Group {
LandmarkRow(landmark: landmarks[0])
LandmarkRow(landmark: landmarks[1])
}
.previewLayout(.fixed(width: 300, height: 70))
}
}
|
List的两种方式:静态数据和动态List
1
2
3
4
5
|
// 静态数据
List {
LandmarkRow(landmark: landmarks[0])
LandmarkRow(landmark: landmarks[1])
}
|
1
2
3
4
5
6
7
8
9
|
// 动态数据,其中landmark必须实现Identifiable
List(landmarks) { landmark in
LandmarkRow(landmark: landmark)
}
// 动态数据,指定id的方式,无需实现Identifiable协议
List(landmarks, id: \.id) { landmark in
LandmarkRow(landmark: landmark)
}
|
NavigationView的title: 仅当组件是NavigationStack的子组件
1
2
3
4
5
6
7
|
NavigationView {
List(landmarks) { landmark in
LandmarkRow(landmark: landmark)
}
.navigationTitle("Landmarks")
.navigationBarTitleDisplayMode(.inline)
}
|
NavigationLink
1
2
3
4
5
6
7
|
List(landmarks) { landmark in
NavigationLink {
LandmarkDetail(landmark: landmark)
} label: {
LandmarkRow(landmark: landmark)
}
}
|
动态生成预览
1
2
3
4
5
6
7
8
|
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
ForEach(["iPhone SE (2nd generation)", "iPhone XS Max"], id: \.self) { deviceName in
LandmarkList()
.previewDevice(PreviewDevice(rawValue: deviceName))
}
}
}
|
1.3 处理用户输入
根据状态过滤数据,显示过滤后的数据
1
2
3
4
5
6
7
|
@State private var showFavoritesOnly = true
var filteredLandmarks: [Landmark] {
landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
|
变更状态
1
2
3
|
Toggle(isOn: $showFavoritesOnly) {
Text("Favorites only")
}
|
在存储中使用ObservableObject: SwiftUI监听ObservableObject的修改去变更视图
ObservableObject基础定义:使用@Published发布数据变更
1
2
3
|
final class ModelData: ObservableObject {
var landmarks: [Landmark] = load("landmarkData.json")
}
|
视图间传递数据: 配合@StateObject和@EnvironmentObject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 初始化
struct LandmarksApp: App {
@StateObject private var modelData = ModelData()
}
// 声明引用
struct LandmarkList: View {
@EnvironmentObject var modelData: ModelData
}
// 传递
ContentView()
.environmentObject(modelData)
LandmarkList()
.environmentObject(modelData)
|