Highlight
MapKit 工程师 Jeff 用不到 30 分钟从零构建了一个完整的波士顿旅行规划应用,展示了 SwiftUI 版 MapKit 如何通过 MapContentBuilder 闭包和声明式 API 大幅降低地图集成门槛。
核心内容
在 SwiftUI 中使用地图曾经是个麻烦事。UIKit 时代的 MKMapView 需要桥接,自定义标注和覆盖物要写大量委托代码,相机控制更是需要手动计算区域和缩放级别。
(01:42)Jeff 的演示从一个空 SwiftUI 项目开始。导入 MapKit,加一行 Map(),一个可交互的地图就出现了。没有委托,没有配置,没有桥接。
(02:41)标注内容通过 MapContentBuilder 闭包添加,语法和往 List 里加 View 几乎一样。Marker 显示标准气球图标,Annotation 则可以放任意 SwiftUI View。地图会自动调整视野框住所有内容——这是默认行为,不需要手动计算。
(04:36)地图样式用 mapStyle 修饰符切换。标准地图默认是平面展示,加上 .standard(elevation: .realistic) 后地形有了真实高程,桥梁和湖泊立刻有了立体感。还可以切到卫星图或混合模式。
(09:10)相机控制通过 MapCameraPosition 状态实现。automatic 让地图自动框住内容,region 显示指定区域,item 聚焦某个地点,userLocation 跟随用户位置。当用户手动拖拽地图后,状态变为 positionedByUser,应用可以据此判断是否需要重新定位。
(17:33)选择交互只需给 Map 加一个 selection 绑定。Marker 会自动显示选中动画。配合 onChange 可以在选中时获取路线、显示 Look Around 街景预览。
(21:54)覆盖物同样通过内容构建器添加。MapPolyline 显示路线,MapPolygon 和 MapCircle 标记区域。每个覆盖物可以指定 aboveRoads 或 aboveLabels 层级,控制与地图标签的叠放关系。
(23:47)地图控件包括 MapUserLocationButton、MapCompass 和 MapScaleView,通过 mapControls 修饰符自动布局。也可以当作普通 View 手动放置,此时需要用 mapScope 关联到特定地图实例。
详细内容
最小可用地图
import MapKit
import SwiftUI
struct ContentView: View {
var body: some View {
Map()
}
}
关键点:
- 一行代码获得可交互地图,支持拖拽、缩放、旋转
- 自动处理用户定位授权和指南针方向
添加标注和自定义视图
struct ContentView: View {
var body: some View {
Map {
// 标准 Marker,气球图标
Marker("Parking", coordinate: .parkingGarage)
// 自定义 Annotation,放任意 SwiftUI View
Annotation("Custom Spot", coordinate: .customSpot) {
ZStack {
Circle().fill(.blue)
Image(systemName: "car.fill")
}
}
}
}
}
关键点:
Marker适合简单地点标记,系统自动处理图标和颜色Annotation的闭包里可以写完整的 SwiftUI 视图层级- 用
anchor: .bottom让视图底部对准坐标点,而非中心对准
基于搜索结果的动态标注
struct ContentView: View {
@State private var searchResults: [MKMapItem] = []
@State private var position: MapCameraPosition = .automatic
var body: some View {
Map(position: $position) {
ForEach(searchResults, id: \.self) { item in
Marker(item: item)
}
}
.onChange(of: searchResults) {
position = .automatic
}
}
func search(for query: String) {
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = query
request.region = visibleRegion
MKLocalSearch(request: request).start { response, _ in
searchResults = response?.mapItems ?? []
}
}
}
关键点:
Marker(item:)自动使用 MKMapItem 的名称、图标和色调- 搜索海滩会显示伞形图标,搜索游乐场显示滑梯图标
position = .automatic让地图自动缩放到展示所有结果- 用户拖拽后搜索,需要手动重置 position 才能重新框选
相机位置状态
@State private var position: MapCameraPosition = .region(.boston)
// 显示指定区域
position = .region(MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 42.36, longitude: -71.06),
span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
))
// 跟随用户位置,未授权时回退到指定区域
position = .userLocation(fallback: .region(.boston))
// 显示某个地点,自动计算合适的缩放级别
position = .item(MKMapItem(placemark: MKPlacemark(coordinate: .beach)))
关键点:
MapCameraPosition是值类型,通过绑定与 Map 双向同步- 用户交互后状态变为
positionedByUser,应用可以检测并响应 onMapCameraChange获取当前可见区域,支持连续更新或仅在交互结束时触发
路线覆盖物
Map {
if let route {
MapPolyline(route.polyline)
.stroke(.blue, lineWidth: 5)
}
}
// 获取路线
func getRoute(from source: MKMapItem, to destination: MKMapItem) {
let request = MKDirections.Request()
request.source = source
request.destination = destination
MKDirections(request: request).calculate { response, _ in
route = response?.routes.first
}
}
关键点:
MapPolyline直接接受MKPolyline,不需要坐标转换StrokeStyle支持虚线、渐变等效果MapPolygon和MapCircle用于标记区域,可通过aboveRoads/aboveLabels控制覆盖物与道路、标签的叠放关系;aboveRoads会让地图标签压在覆盖物之上,aboveLabels会让覆盖物压在标签之上
地图控件
Map {
// 内容
}
.mapControls {
MapUserLocationButton()
MapCompass()
MapScaleView()
}
关键点:
mapControls自动在合适位置布局控件- 手动放置时用
mapScope关联:.mapScope(mapScope) - macOS 额外提供
MapZoomStepper和MapPitchSlider
核心启发
-
给本地生活类 app 加一张可交互地图:餐厅、酒店、活动类应用可以用 MapKit for SwiftUI 快速实现”附近推荐”功能。Marker 自动显示类别图标,Look Around 提供街景预览,用户不需要离开应用就能判断地点是否合适。
-
用地图做数据可视化:如果应用有地理位置相关的数据(如配送轨迹、运动路线、旅行足迹),用
MapPolyline和自定义 Annotation 直接展示在地图上,比列表更直观。配合onMapCameraChange可以只加载当前视野内的数据点。 -
做一款旅行规划工具:参考 session 中的波士顿行程规划思路——用搜索找景点、用 Marker 标记、用路线连接、用 Look Around 预览。SwiftUI 的声明式语法让这种多步骤交互的实现成本大幅降低。
关联 Session
- What’s new in SwiftUI — SwiftUI 今年的动画、数据流和预览改进
- Q&A: Maps technologies — MapKit、MapKit for SwiftUI 和地图技术的工程答疑
- Meet the Presenter: Meet MapKit for SwiftUI — 这场 MapKit for SwiftUI 演讲的配套 watch party 和问答
评论
GitHub Issues · utterances