SwiftUI 在 WWDC 2020 新加的 Map 组件虽然没有 UIViewRepresentable 自定义包的功能丰富,但也可以做一些复杂的需求了,比如获取当前位置。
Map 的参数里 coordinateRegion
是一个 MKCoordinateRegion 的 Binding,地图移动的时候会反馈到 Binding 里面,不用再去想办法做类似于 WKMapView.Appearance.delegate 之类的全局 hack 了,只用声明一个 ObservableObject 然后在里面写 didSet:
final class MapConfig: ObservableObject
{
var region: MKCoordinateRegion = MKCoordinateRegion(...)
{
didSet {
print("\(region)")
}
}
}
有 didSet 后就可以做一些跟随功能,比如放一个 Pin 一直跟随用户拖动:
import SwiftUI
import MapKit
struct MapAnnotationModel: Identifiable {
var coordinate: CLLocationCoordinate2D
let id = UUID()
}
final class MapConfig: ObservableObject
{
var region: MKCoordinateRegion = MKCoordinateRegion(center: CLLocationCoordinate2DMake(37.8, -122.5), latitudinalMeters: 5000, longitudinalMeters: 5000)
{
didSet {
annotationItems = [MapAnnotationModel(coordinate: region.center)] // 替换 annotationItems 为新的带有 region center 的数组
self.objectWillChange.send() // 提醒 UI 更新
}
}
@Published var annotationItems: [MapAnnotationModel] = [] // 默认空
}
struct ChooseLocationView: View {
@ObservedObject var config = MapConfig()
var body: some View {
Map(coordinateRegion: $config.region,
interactionModes: .all,
showsUserLocation: true,
userTrackingMode: nil,
annotationItems: config.annotationItems)
{ item in
MapPin(coordinate: item.coordinate)
}
.edgesIgnoringSafeArea(.all)
.navigationTitle("Choose Location")
}
}