SwiftUI 与 MapKit 的集成在今年发生了重大变化。在之前的 SwiftUI 版本中,我们将 MKMapView 的基本功能封装到名为 Map 的 SwiftUI 视图中。幸运的是,事情发生了变化,SwiftUI 引入了与 MapKit 集成的新 API。本篇文章我们将学习如何在 SwiftUI 的最新版本中使用可用的新功能丰富的 API 与 MapKit 集成。
正如我之前所说,在 SwiftUI 框架的早期版本中,我们有一个 Map 视图,为我们提供了 MapKit 的基本功能,该功能现在已被弃用。在面向较早 Apple 平台版本的情况下,仍然使用已弃用的 Map 视图是有意义的。
新的 MapKit API 引入了 MapContentBuilder 结果构建器,它看起来类似于 ViewBuilder,但是使用符合 MapContent 协议的类型。让我们从使用 SwiftUI 中最新迭代中提供的新 MapKit API 集成的基本示例开始。
import MapKit
import SwiftUI
extension 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 的基础知识。在接下来的几周里,我们将继续讨论相机操作、地图控件和其他高级主题。希望你喜欢这篇文章。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。