SwiftUI Map 获取当前地图位置

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")
    }
}