文章目录
- 前言
- 新 MapKit API 的引入
- 控制初始地图位置
- 相机位置的双向绑定
- 总结
前言
SwiftUI 与 MapKit 的集成在今年发生了重大变化。在之前的 SwiftUI 版本中,我们将 MKMapView 的基本功能封装到名为 Map 的 SwiftUI 视图中。幸运的是,事情发生了变化,SwiftUI 引入了与 MapKit 集成的新 API。本篇文章我们将学习如何在 SwiftUI 的最新版本中使用可用的新功能丰富的 API 与 MapKit 集成。
正如我之前所说,在 SwiftUI 框架的早期版本中,我们有一个 Map 视图,为我们提供了 MapKit 的基本功能,该功能现在已被弃用。在面向较早 Apple 平台版本的情况下,仍然使用已弃用的 Map 视图是有意义的。
新 MapKit API 的引入
新的 MapKit API 引入了 MapContentBuilder 结果构建器,它看起来类似于 ViewBuilder,但是使用符合 MapContent 协议的类型。让我们从使用 SwiftUI 中最新迭代中提供的新 MapKit API 集成的基本示例开始。
import MapKit
import SwiftUIextension CLLocationCoordinate2D {static let newYork: Self = .init(latitude: 40.730610,longitude: -73.935242)static let seattle: Self = .init(latitude: 47.608013,longitude: -122.335167)static let sanFrancisco: Self = .init(latitude: 37.733795,longitude: -122.446747)
}struct ContentView: View {var body: some View {Map {Annotation("Seattle", coordinate: .seattle) {Image(systemName: "mappin").foregroundStyle(.black).padding().background(.red).clipShape(Circle())}Marker(coordinate: .newYork) {Label("New York", systemImage: "mappin")}Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco)}}
}
正如你在上面的示例中看到的,我们通过使用 MapContentBuilder 闭包定义地图,并在其上放置内容。MapContentBuilder 类型与符合 MapContent 协议的任何类型一起使用。
在我们的示例中,我们使用了 Marker 和 Annotation 类型。Marker 是一个基本项,允许我们在地图上放置预定义的标记。Annotation 类型更先进,将使我们能够使用纬度和经度在地图上放置 SwiftUI 视图。
SwiftUI 为我们提供了许多符合 MapContent 协议的类型。我们已经使用了其中的两个:Marker 和 Annotation。其中许多包括 MapCircle、MapPolygon、MapPolyline、UserAnnotation 等。
struct ContentView: View {var body: some View {Map {Annotation("Seattle", coordinate: .seattle) {Image(systemName: "mappin").foregroundStyle(.black).padding().background(.red).clipShape(Circle())}Marker(coordinate: .newYork) {Label("New York", systemImage: "mappin")}UserAnnotation()}}
}
控制初始地图位置
你可以通过使用 Map 初始化器的另一个重载来控制地图的初始位置,该初始化器提供 initialPosition 参数。
struct ContentView: View {let initialPosition: MapCameraPosition = .userLocation(fallback: .camera(MapCamera(centerCoordinate: .newYork, distance: 0)))var body: some View {Map(initialPosition: initialPosition) {Annotation("Seattle", coordinate: .seattle) {Image(systemName: "mappin").foregroundStyle(.black).padding().background(.red).clipShape(Circle())}Marker(coordinate: .newYork) {Label("New York", systemImage: "mappin")}Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco)}}
}
initialPosition 参数接受 MapCameraPosition 类型的实例。MapCameraPosition 允许我们以几种方式定义地图位置。它可以是我们在示例中使用的用户位置,或者你可以使用 camera、region、rect 或 item 等静态函数将其指向地图上的任何区域。默认情况下,它使用 MapCameraPosition 类型的自动实例,该类型适合地图内容。
相机位置的双向绑定
每当你需要对相机位置有恒定的控制时,你可以使用 Map 初始化器的另一个重载,允许你提供与地图相机位置的双向绑定。
struct ContentView: View {@State private var position: MapCameraPosition = .userLocation(fallback: .camera(MapCamera(centerCoordinate: .newYork, distance: 0)))var body: some View {Map(position: $position) {// ...}}
}
SwiftUI 在用户拖动地图时更新位置绑定。它还在你以编程方式更新 position 属性时立即更新地图相机位置。
struct ContentView: View {@State private var position: MapCameraPosition = .userLocation(fallback: .camera(MapCamera(centerCoordinate: .newYork, distance: 0)))var body: some View {Map(position: $position, interactionModes: .pitch) {// ...}}
}
通过使用 interactionModes 参数,你可以控制与地图允许的交互类型。MapInteractionModes 类型定义了一组交互,如平移、俯仰、旋转和缩放。默认情况下,它启用所有可用的交互类型。
总结
今天,我们学习了在 SwiftUI 中集成 MapKit 的基础知识。在接下来的几周里,我们将继续讨论相机操作、地图控件和其他高级主题。希望你喜欢这篇文章。