认识 SwiftUI 版 MapKit
Meet MapKit for SwiftUI
2023年6月5日
一句话判断
一行代码就能在 SwiftUI 中嵌入交互式地图——然后通过 Marker、Annotation、Look Around、路线叠加、真实地形等功能,构建出完整的地图体验。这场 Session 用一个波士顿旅行规划器从零演示了全部能力。
这场 Session 讲了什么
MapKit 团队的 Jeff 通过构建一个完整的波士顿旅行规划应用,展示了 SwiftUI 版 MapKit 的全套能力。
核心是 MapKit for SwiftUI 的大幅扩展。过去在 SwiftUI 中使用地图功能受限,现在通过 MapContentBuilder 闭包,可以像在 List 中添加 View 一样在地图上添加内容。
Session 覆盖了以下功能:Marker(标记点,标准气球样式)、Annotation(自定义 SwiftUI View 标记)、地图样式切换(标准/卫星/混合)、真实地形高程、Look Around 街景集成、路线叠加(driving route overlay)、搜索结果展示、标记选择交互、用户位置按钮等地图控件。
地图会自动调整视野来展示所有添加的内容。搜索结果使用 MKMapItem 类型的 Marker,自动显示对应的图标和颜色(如海滩显示伞形图标)。
值得深挖的点
MapContentBuilder 的设计哲学:和 SwiftUI 的 ViewBuilder 一样,MapContentBuilder 使用结果构建器模式。你可以在闭包中用 ForEach 遍历数据添加多个标记或叠加层。所有地图内容类型(Marker、Annotation、Overlay)都用同一个 builder 添加。
Marker vs Annotation 的选择:Marker 使用系统标准气球样式,支持自动图标和着色——配合 MKMapItem 使用时尤其方便,系统会自动选择合适的图标。Annotation 则完全自定义——你提供一个 SwiftUI View,它被渲染在地图的指定坐标上。
safeAreaInset 的正确使用:在地图上方叠加自定义 UI 时,用 safeAreaInset 确保不会遮挡地图内容、Apple Maps logo 和法律链接。这是 MapKit SwiftUI 集成中的一个重要细节。
Look Around 集成:可以在地图中直接嵌入 Look Around 街景视图,让用户在规划行程时预览目的地。这是 MapKit 中之前需要大量代码才能实现的功能。
代码片段
// 一行代码嵌入交互式地图
Map { }
// 使用 MapContentBuilder 添加标记
Map {
Marker("Parking", coordinate: parkingCoordinate)
.tint(.blue)
// 自定义 SwiftUI View 作为标记
Annotation("Start", coordinate: startCoordinate, anchor: .bottom) {
ZStack {
Circle().fill(.blue)
Image(systemName: "figure.walk")
}
}
}
.mapStyle(.standard(elevation: .realistic)) // 启用真实地形
// 搜索并展示结果
@State private var searchResults: [MKMapItem] = []
Map {
ForEach(searchResults, id: \.self) { item in
Marker(item: item) // 自动使用 map item 的图标和颜色
}
}
.safeAreaInset(edge: .bottom) {
// 搜索按钮,不遮挡地图内容
HStack {
Button("Playgrounds") { search("playground") }
Button("Beaches") { search("beach") }
}
.padding()
}
func search(_ query: String) {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = query
request.region = MKCoordinateRegion(
center: parkingCoordinate,
span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
)
MKLocalSearch(request: request).start { response, _ in
searchResults = response?.mapItems ?? []
}
}
// 路线叠加和地图样式
Map {
Marker("Beach", coordinate: beachCoordinate)
MapPolyline(route.polylines.first!)
.stroke(.blue, lineWidth: 5)
}
.mapStyle(.imagery) // 卫星图
.mapControls {
MapUserLocationButton() // 用户位置按钮
MapCompass() // 指南针
}
最佳实践
- 配合 MKMapItem 使用 Marker:搜索结果直接用
Marker(item: mapItem)创建,系统自动提供合适的图标、颜色和标题。 - 用 safeAreaInset 叠加 UI:不要用 ZStack 叠加,用 safeAreaInset 确保地图内容和系统控件不被遮挡。
- 根据场景选择地图样式:标准地图适合导航和搜索,卫星图适合展示地点环境,混合模式兼顾两者。
- 开启真实地形增强沉浸感:
elevation: .realistic让地图从平面变成有立体感的体验,特别适合旅行和户外应用。 - 利用自动视野调整:地图会自动缩放到合适的级别展示所有内容。如果需要手动控制,可以通过 camera position 相关 API 设置。
还有什么值得关注
- MapKit for SwiftUI 现在支持所有 Apple 平台,包括 watchOS 和 tvOS。
- Look Around 街景可以在地图视图内嵌入,也可以作为独立的全屏体验展示。
- MapPolyline 支持自定义样式(颜色、线宽),可以展示驾车、步行等不同类型的路线。
- Session 中的旅行规划器是一个很好的参考项目,展示了如何将搜索、标记、路线、街景等功能组合在一起。
- 新的 Map Controls API(MapUserLocationButton、MapCompass 等)让地图控件的添加变得和普通 SwiftUI 按钮一样简单。