Google 将 SDK iOS 映射到用户启动时的当前位置 Swift SwiftUI

Google Maps iOS SDK to user's current location on launch Swift SwiftUI

我正在尝试模仿 Google 地图的某些功能,在启动应用程序时,如果已授予所需的权限,相机将移动到用户的当前位置。

我已经使用自定义当前位置按钮实现了此功能,该按钮可以很好地将相机带到用户当前位置,但无法在启动时模仿它。地图在位置管理器之后初始化,但是,调用 didUpdateLocations 有延迟。这意味着它发生在地图完成初始化之后,因此 initialiseMapCamera() 默认为坐标 0,0。如果没有正确的烫发,地图相机默认为 1,1,正如预期的那样。

我确定有一个我没有想到的解决此问题的明显方法;非常感谢任何帮助。谢谢!

LocationManager - 首先实例化

class LocationManager: NSObject, ObservableObject {
  
  private let locationManager = CLLocationManager()
  
  @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined {
    willSet { objectWillChange.send() }
  }
  
  @Published var location: CLLocation? {
    willSet { objectWillChange.send() }
  }
  
  var latitude: CLLocationDegrees {
    return location?.coordinate.latitude ?? 0
  }
  
  var longitude: CLLocationDegrees {
    return location?.coordinate.longitude ?? 0
  }
  
  override init() {
    super.init()
    
    locationManager.delegate = self
    
    switch authorizationStatus {
    case .authorizedAlways, .authorizedWhenInUse:
      configureLocationSettings()
    case .notDetermined, .restricted, .denied: break
    @unknown default: fatalError()
    }
  }
  
  func configureLocationSettings() {
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingLocation()
  }
  
  func requestLocationPermissions() {
    locationManager.requestWhenInUseAuthorization()
  }
}

extension LocationManager: CLLocationManagerDelegate {

  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.last else { return }
    self.location = location
  }
  
  func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    self.authorizationStatus = manager.authorizationStatus

    switch authorizationStatus {
    case .authorizedAlways, .authorizedWhenInUse:
      configureLocationSettings()
    case .notDetermined, .restricted, .denied: return
    @unknown default: 
      fatalError()
    }
  }
}

MapViewBridge - 之后实例化

struct MapViewControllerBridge: UIViewControllerRepresentable {
  
  @EnvironmentObject var locationManager: LocationManager
  @EnvironmentObject var mapViewModel: mapViewModel

  func makeUIViewController(context: Context) -> MapViewController {
    let uiViewController = MapViewController()
    initialiseMapCamera(mapView: uiViewController.mapView)
    return uiViewController
  }

  func updateUIViewController(_ uiViewController: MapViewController, context: Context) { 
    cameraToLocationButton(mapView: uiViewController.mapView)
  }
  
  private func initialiseMapCamera(mapView: GMSMapView) {
    var cameraLocation: CLLocationCoordinate2D
    
    switch locationManager.authorizationStatus {
    case .authorizedAlways, .authorizedWhenInUse:
      cameraLocation = CLLocationCoordinate2D(
        latitude: locationManager.latitude,
        longitude: locationManager.longitude)
    case .notDetermined, .restricted, .denied:
      cameraLocation = CLLocationCoordinate2D(latitude: 1.0, longitude: 1.0)
    @unknown default:
      fatalError()
    }
    mapView.camera = GMSCameraPosition.camera(withTarget: cameraLocation, zoom: defaultZoomLevel)
  }
  
  private func animateCameraToCurrentLocation(mapView: GMSMapView) {
    let currentLocation = CLLocationCoordinate2D(
      latitude: locationManager.latitude,
      longitude: locationManager.longitude)
    mapView.animate(with: GMSCameraUpdate.setTarget(currentLocation))
    mapView.animate(toZoom: defaultZoomLevel)
  }
  
  private func cameraToLocationButton(mapView: GMSMapView) {
    guard mapViewModel.cameraToLocation else {
      return
    }

    switch locationManager.authorizationStatus {
    case .authorizedWhenInUse, .authorizedAlways:
      animateCameraToCurrentLocation(mapView: mapView)
    case .notDetermined:
      locationManager.requestLocationPermissions()
    case .restricted, .denied:
      DispatchQueue.main.async {
        mapViewModel.showLocationSettingsAlert = true
      }
    @unknown default:
      fatalError()
    }
    
    DispatchQueue.main.async {
      mapViewModel.cameraToLocation = false
    }
  }
}

在更新位置之前创建加载视图。然后一旦更新禁用加载视图并显示地图,它将在地图视图出现时开始相机移动。