简体   繁体   English

谷歌地图 iOS SDK 到用户在启动时的当前位置 Swift Z5D807DF8E2D0F6FCC3B5037BZ8AB9

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

I'm trying to mimic some functionality of Google Maps, where upon launching the app, the camera is moved to the current location of the user, provided the required perms have been granted.我试图模仿谷歌地图的一些功能,在启动应用程序时,如果已授予所需的权限,相机就会移动到用户的当前位置。

I have implemented this using a custom current location button, which works fine taking the camera to the users current location, but can't mimic this on launch.我已经使用自定义当前位置按钮实现了这一点,该按钮可以很好地将相机带到用户当前位置,但在启动时无法模仿。 The map initialises after the location manager, however, there is a delay in calling didUpdateLocations. map 在位置管理器之后初始化,但是调用 didUpdateLocations 时会有延迟。 This means it happens after the map has finished initialising, so initialiseMapCamera() defaults to coordinates of 0,0.这意味着它发生在 map 完成初始化之后,因此 initialiseMapCamera() 默认坐标为 0,0。 If the correct perms are not in place, the map camera defaults to 1,1, as expected.如果没有正确的烫发,map 相机默认为 1,1,正如预期的那样。

I'm sure there's an obvious way to fix this that I'm not thinking of;我确信有一种明显的方法可以解决我没有想到的问题; any help greatly appreciated.非常感谢任何帮助。 Thanks!谢谢!

LocationManager - instantiated first 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 - instantiated afterwards 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
    }
  }
}

Create a loading view until the location is updated.创建加载视图,直到位置更新。 Then once its updated disable the loading view and show the map and it will begin the camera movement on appearance of the map view.然后一旦更新禁用加载视图并显示 map,它将在 map 视图出现时开始相机移动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM