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

Dar*_*ell 2 mapkit swiftui

我正在使用 Xcode 12。

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

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

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

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

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

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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这里是 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: $0.coordinate)
            }
            .frame(height: 300)
  }
}
Run Code Online (Sandbox Code Playgroud)

jn_*_*pdx 7

这是一种可能的解决方案:

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: $0.coordinate)
        }
        .frame(height: 300)
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我还更改了您的代码以稍微放下引脚。您正在强制展开location,直到位置管理器设置第一个位置为止,该值为零,从而导致崩溃。在我的编辑中,如果还没有位置,它只会返回一个空的注释项数组。