SwiftUI官方文档关键实现

一、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)
0%