SwiftUI mapkit 将区域设置为用户的当前位置

SwiftUI mapkit set region to user's current location

我正在使用 Xcode12.

我能够显示带有区域但带有硬编码值的地图。

相反,我想根据用户的当前位置设置地图区域。

我有一个 LocationManager class,它获取用户的位置并发布它。

我有一个 ShowMapView SwiftUI 视图,它观察基于 LocationManager class 的对象以获取用户的位置。 但是,我不知道如何使用 locationManager 对象中的数据来设置地图使用的区域。

这里是 LocationManager class,它获取用户的位置并发布它。

import Foundation
import MapKit

final class LocationManager: NSObject, ObservableObject {
  @Published var location: CLLocation?
  
  private let locationManager = CLLocationManager()
   
  override init() {
    super.init()
    
    self.locationManager.delegate = self
    
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.distanceFilter = kCLDistanceFilterNone
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.startUpdatingLocation()
  }
}

extension LocationManager: CLLocationManagerDelegate {
  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    if let location = locations.last {
      self.location = location
    }
  }
}

这里是ShowMapView SwiftUI View,需要获取用户发布的位置,设置地图使用的区域。如您所见,这些值目前是硬编码的。

import Combine
import MapKit
import SwiftUI

struct AnnotationItem: Identifiable {
    let id = UUID()
    let name: String
    let coordinate: CLLocationCoordinate2D
}

struct ShowMapView: View {
  @ObservedObject private var locationManager = LocationManager()
  
  @State private var region = MKCoordinateRegion(
    center: CLLocationCoordinate2D(latitude: 38.898150, longitude: -77.034340),
    span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
  )

  var body: some View {
            Map(coordinateRegion: $region, annotationItems: [AnnotationItem(name: "Home", coordinate: CLLocationCoordinate2D(latitude: self.locationManager.location!.coordinate.latitude, longitude: self.locationManager.location!.coordinate.longitude))]) {
               MapPin(coordinate: [=11=].coordinate)
            }
            .frame(height: 300)
  }
}

这里有一个可能的解决方案:

final class LocationManager: NSObject, ObservableObject {
    @Published var location: CLLocation?
    @Published var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 38.898150, longitude: -77.034340),
        span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
    )
    private var hasSetRegion = false
    
    private let locationManager = CLLocationManager()
    
    override init() {
        super.init()
        
        self.locationManager.delegate = self
        
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
        self.locationManager.distanceFilter = kCLDistanceFilterNone
        self.locationManager.requestWhenInUseAuthorization()
        self.locationManager.startUpdatingLocation()
    }
}

extension LocationManager: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            self.location = location
            
            if !hasSetRegion {
                self.region = MKCoordinateRegion(center: location.coordinate,
                                                 span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
                hasSetRegion = true
            }
        }
    }
}

struct ShowMapView: View {
    @ObservedObject private var locationManager = LocationManager()
    
    var homeLocation : [AnnotationItem] {
        guard let location = locationManager.location?.coordinate else {
            return []
        }
        return [.init(name: "Home", coordinate: location)]
    }
    
    var body: some View {
        Map(coordinateRegion: $locationManager.region, annotationItems: homeLocation) {
            MapPin(coordinate: [=10=].coordinate)
        }
        .frame(height: 300)
    }
}

在此解决方案中,区域由位置管理器发布。一旦收到位置,该区域就会以该点为中心(在 didUpdateLocations 中)。然后,设置一个布尔标志,表示该区域最初已居中。设置该布尔值后,它不再更新该区域。这会让用户仍然drag/zoom,等等

我还更改了您的代码以稍微放下图钉。您正在强制展开 location,在位置管理器设置第一个位置之前它是 nil,从而导致崩溃。在我的编辑中,如果还没有位置,它只是 returns 一个空的注释项数组。