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 了。