LandmarkDetail
如今依然使用硬編碼的數據來顯示地標。像 LandmarkRow
同樣,LandmarkDetail
類型和它組合的其餘 view 都須要一個 landmark
屬性做爲它們的數據源。git
在開始子 view 的內容時,咱們會把 CircleImage
、 MapView
和 LandmarkDetail
的顯示從硬編碼改成傳入的數據。SwiftUI 官方教程swift
7.1 在 CircleImage.swif
中,添加存儲屬性 image
。SwiftUI教程數組
這是使用 SwiftUI
構建 view 時的常見模式。咱們的自定義 view 一般會爲特定視圖包裝和封裝一些 modifiers
。session
CircleImage.swiftapp
import SwiftUI struct CircleImage: View { var image: Image var body: some View { image .clipShape(Circle()) .overlay(Circle().stroke(Color.white, lineWidth: 4)) .shadow(radius: 10) } } struct CircleImage_Preview: PreviewProvider { static var previews: some View { CircleImage() } }
7.2 更新 preview provider
,傳遞一個 Turtle Rock
的圖片。ide
CircleImage.swiftthis
import SwiftUI struct CircleImage: View { var image: Image var body: some View { image .clipShape(Circle()) .overlay(Circle().stroke(Color.white, lineWidth: 4)) .shadow(radius: 10) } } struct CircleImage_Preview: PreviewProvider { static var previews: some View { CircleImage(image: Image("turtlerock")) } }
7.3 在 MapView.swift
中,給 MapView
添加一個 coordinate
屬性,而後把經緯度的硬編碼換成使用這個屬性。SwiftUI教程編碼
MapView.swiftspa
import SwiftUI import MapKit struct MapView: UIViewRepresentable { var coordinate: CLLocationCoordinate2D func makeUIView(context: Context) -> MKMapView { MKMapView(frame: .zero) } func updateUIView(_ view: MKMapView, context: Context) { let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02) let region = MKCoordinateRegion(center: coordinate, span: span) view.setRegion(region, animated: true) } } struct MapView_Preview: PreviewProvider { static var previews: some View { MapView() } }
7.4 更新 preview provider
,傳遞數據數組中第一個地標的座標。code
MapView.swift
import SwiftUI import MapKit struct MapView: UIViewRepresentable { var coordinate: CLLocationCoordinate2D func makeUIView(context: Context) -> MKMapView { MKMapView(frame: .zero) } func updateUIView(_ view: MKMapView, context: Context) { let span = MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02) let region = MKCoordinateRegion(center: coordinate, span: span) view.setRegion(region, animated: true) } } struct MapView_Preview: PreviewProvider { static var previews: some View { MapView(coordinate: landmarkData[0].locationCoordinate) } }
7.5 在 LandmarkDetail.swift
中,SwiftUI教程 給 LandmarkDetail
類型添加 landmark
屬性。
LandmarkDetail.swift
import SwiftUI struct LandmarkDetail: View { var landmark: Landmark var body: some View { VStack { MapView() .frame(height: 300) CircleImage() .offset(y: -130) .padding(.bottom, -130) VStack(alignment: .leading) { Text("Turtle Rock") .font(.title) HStack(alignment: .top) { Text("Joshua Tree National Park") .font(.subheadline) Spacer() Text("California") .font(.subheadline) } } .padding() Spacer() } } } struct LandmarkDetail_Preview: PreviewProvider { static var previews: some View { LandmarkDetail() } }
7.6 更新 preview provider
,使用 landmarkData
中的第一個地標。
LandmarkDetail.swift
import SwiftUI struct LandmarkDetail: View { var landmark: Landmark var body: some View { VStack { MapView() .frame(height: 300) CircleImage() .offset(y: -130) .padding(.bottom, -130) VStack(alignment: .leading) { Text("Turtle Rock") .font(.title) HStack(alignment: .top) { Text("Joshua Tree National Park") .font(.subheadline) Spacer() Text("California") .font(.subheadline) } } .padding() Spacer() } } } struct LandmarkDetail_Preview: PreviewProvider { static var previews: some View { LandmarkDetail(landmark: landmarkData[0]) } }
7.7 將所需數據傳遞給咱們的自定義類型。
LandmarkDetail.swift
import SwiftUI struct LandmarkDetail: View { var landmark: Landmark var body: some View { VStack { MapView(coordinate: landmark.locationCoordinate) .frame(height: 300) CircleImage(image: landmark.image(forSize: 250)) .offset(y: -130) .padding(.bottom, -130) VStack(alignment: .leading) { Text(landmark.name) .font(.title) HStack(alignment: .top) { Text(landmark.park) .font(.subheadline) Spacer() Text(landmark.state) .font(.subheadline) } } .padding() Spacer() } } } struct LandmarkDetail_Preview: PreviewProvider { static var previews: some View { LandmarkDetail(landmark: landmarkData[0]) } }
7.8 最後,調用 navigationBarTitle(_:displayMode:)
方法,給導航欄添加顯示詳情 view 時的標題。
LandmarkDetail.swift
import SwiftUI struct LandmarkDetail: View { var landmark: Landmark var body: some View { VStack { MapView(coordinate: landmark.locationCoordinate) .frame(height: 300) CircleImage(image: landmark.image(forSize: 250)) .offset(y: -130) .padding(.bottom, -130) VStack(alignment: .leading) { Text(landmark.name) .font(.title) HStack(alignment: .top) { Text(landmark.park) .font(.subheadline) Spacer() Text(landmark.state) .font(.subheadline) } } .padding() Spacer() } .navigationBarTitle(Text(landmark.name), displayMode: .inline) } } struct LandmarkDetail_Preview: PreviewProvider { static var previews: some View { LandmarkDetail(landmark: landmarkData[0]) } }
7.9 在 SceneDelegate.swift
中,把 app 的 rootView
改爲 LandmarkList
。
當咱們不使用預覽而是在模擬器中獨立運行 app 時,app 會以 SceneDelegate
中定義的 rootView
開始顯示。
SceneDelegate.swift
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Use a UIHostingController as window root view controller let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIHostingController(rootView: LandmarkList()) self.window = window window.makeKeyAndVisible() } // ... }
7.10 在 LandmarkList.swift
中,給目標 LandmarkDetail
傳遞當前的地標。
LandmarkList.swift
import SwiftUI struct LandmarkList: View { var body: some View { NavigationView { List(landmarkData) { landmark in NavigationButton(destination: LandmarkDetail(landmark: landmark)) { LandmarkRow(landmark: landmark) } } .navigationBarTitle(Text("Landmarks")) } } } struct LandmarkList_Previews: PreviewProvider { static var previews: some View { LandmarkList() } }
7.11 切換到實時預覽,能夠查看從列表導航到正確的地標詳情 view 了。