简体   繁体   English

在地图上显示用户位置 SwiftUI

[英]Show user location on map SwiftUI

I am trying to load a map and have the initial location on user's location as well as showing the user's location on the map using SwiftUI.我正在尝试加载地图并在用户位置上显示初始位置,并使用 SwiftUI 在地图上显示用户的位置。 I don't know how to do that in SwiftUI.我不知道如何在 SwiftUI 中做到这一点。

I have tried to put 'view.showsUserLocation = true' in updateUIView function but it is not working.我试图将 'view.showsUserLocation = true' 放在 updateUIView 函数中,但它不起作用。

import SwiftUI
import MapKit
struct MapView : UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }

    func updateUIView(_ view: MKMapView, context: Context) {
        view.showsUserLocation = true
        let coordinate = CLLocationCoordinate2D(
            latitude: 34.011286, longitude: -116.166868)
        let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)

        let region = MKCoordinateRegion(center: view.userLocation.location?.coordinate ?? coordinate, span: span)
        view.setRegion(region, animated: true)
    }
}

The location comes nil when I tried to print it.当我尝试打印它时,该位置为零。

Add key Privacy - Location When In Use Usage Description and description in Info.plistInfo.plist添加密钥Privacy - Location When In Use Usage Description和说明

Then try with updating below function:然后尝试更新以下功能:

func updateUIView(_ view: MKMapView, context: Context) {

    view.showsUserLocation = true

    // Ask for Authorisation from the User.
    self.locationManager.requestAlwaysAuthorization()

    // For use in foreground
    self.locationManager.requestWhenInUseAuthorization()

    if CLLocationManager.locationServicesEnabled() {
        //        self.locationManager.delegate = self
         self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
         self.locationManager.startUpdatingLocation()

        //Temporary fix: App crashes as it may execute before getting users current location
        //Try to run on device without DispatchQueue

        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
            let locValue:CLLocationCoordinate2D = self.locationManager.location!.coordinate
            print("CURRENT LOCATION = \(locValue.latitude) \(locValue.longitude)")

            let coordinate = CLLocationCoordinate2D(
                latitude: locValue.latitude, longitude: locValue.longitude)
            let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
            let region = MKCoordinateRegion(center: coordinate, span: span)
            view.setRegion(region, animated: true)

        })
    }

}

The above codes will cause the app crash because of the inappropriate permission request.以上代码会因为权限请求不当导致应用程序崩溃。 Use the below code for better performance and on-time permission.使用以下代码以获得更好的性能和准时许可。

struct MapView: UIViewRepresentable {
    let locationManager = CLLocationManager()        
    
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
    
    func updateUIView(_ view: MKMapView, context: Context) {
        view.showsUserLocation = true
        let status = CLLocationManager.authorizationStatus()
        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()
        
        if status == .authorizedAlways || status == .authorizedWhenInUse {
            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.startUpdatingLocation()
            let location: CLLocationCoordinate2D = locationManager.location!.coordinate
            let span = MKCoordinateSpan(latitudeDelta: 0.009, longitudeDelta: 0.009)
            let region = MKCoordinateRegion(center: location, span: span)
            view.setRegion(region, animated: true)
        }
    }
    
}

try this one:试试这个:

struct OriginMap : UIViewRepresentable {




 func makeUIView(context: UIViewRepresentableContext<OriginMap>) -> MKMapView{
    MKMapView()
}




 func updateUIView(_ mapView: MKMapView, context: Context) {
    let locationManager = CLLocationManager()


    mapView.showsUserLocation = true

    locationManager.requestAlwaysAuthorization()

    locationManager.requestWhenInUseAuthorization()

    if CLLocationManager.locationServicesEnabled() {
        locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        locationManager.startUpdatingLocation()

        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
            let locValue:CLLocationCoordinate2D = locationManager.location!.coordinate


            let coordinate = CLLocationCoordinate2D(
                latitude: locValue.latitude, longitude: locValue.longitude)
            Datas.currentLocation = coordinate


            let span = MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002)
            let region = MKCoordinateRegion(center: coordinate, span: span)
            mapView.setRegion(region, animated: true)


        })
    }}

This is the cleanest way I have found to setup CoreLocation and MapView.这是我发现设置 CoreLocation 和 MapView 的最干净的方法。 First, you have to create an UIViewRepresentable to use CoreLocation in SwiftUI.首先,您必须创建一个 UIViewRepresentable 才能在 SwiftUI 中使用 CoreLocation。

Do not forget to enable in your Info.plist file this Privacy with a message:不要忘记在您的 Info.plist 文件中启用带有消息的隐私:

Privacy - Location Always and When In Use Usage Description隐私 - 位置始终和使用时使用说明

Privacy - Location When In Use Usage Description隐私 - 使用时的位置 使用说明

Privacy - Location Always Usage Description隐私 - 位置始终使用说明

import SwiftUI
import MapKit

// MARK: Struct that handle the map
struct MapView: UIViewRepresentable {

  @Binding var locationManager: CLLocationManager
  @Binding var showMapAlert: Bool

  let map = MKMapView()

  ///Creating map view at startup
  func makeUIView(context: Context) -> MKMapView {
    locationManager.delegate = context.coordinator
    return map
  }

  func updateUIView(_ view: MKMapView, context: Context) {
    map.showsUserLocation = true
    map.userTrackingMode = .follow
  }

  ///Use class Coordinator method
  func makeCoordinator() -> MapView.Coordinator {
    return Coordinator(mapView: self)
  }

  //MARK: - Core Location manager delegate
  class Coordinator: NSObject, CLLocationManagerDelegate {

    var mapView: MapView

    init(mapView: MapView) {
      self.mapView = mapView
    }

    ///Switch between user location status
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
      switch status {
      case .restricted:
        break
      case .denied:
        mapView.showMapAlert.toggle()
        return
      case .notDetermined:
        mapView.locationManager.requestWhenInUseAuthorization()
        return
      case .authorizedWhenInUse:
        return
      case .authorizedAlways:
        mapView.locationManager.allowsBackgroundLocationUpdates = true
        mapView.locationManager.pausesLocationUpdatesAutomatically = false
        return
      @unknown default:
        break
      }
      mapView.locationManager.startUpdatingLocation()
    }
   }
  }
 }

This is the way I use it in my SwiftUI view.这是我在 SwiftUI 视图中使用它的方式。 An alert is toggle in case the permission is denied in the Coordinator class switch:如果在 Coordinator 类开关中拒绝权限,则会切换警报:

import SwiftUI
import CoreLocation

// MARK: View that shows map to users
struct HomeView: View {

  @State var locationManager = CLLocationManager()
  @State var showMapAlert = false

  var body: some View {
    MapView(locationManager: $locationManager, showMapAlert: $showMapAlert)
        .alert(isPresented: $showMapAlert) {
          Alert(title: Text("Location access denied"),
                message: Text("Your location is needed"),
                primaryButton: .cancel(),
                secondaryButton: .default(Text("Settings"),
                                          action: { self.goToDeviceSettings() }))
    }
  }
}

extension HomeView {
  ///Path to device settings if location is disabled
  func goToDeviceSettings() {
    guard let url = URL.init(string: UIApplication.openSettingsURLString) else { return }
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
  }
}

Here is the code for SwiftUI2这是 SwiftUI2 的代码

import MapKit
import SwiftUI

struct MapView: View {
    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.4353, longitude: 35.23442), span: MKCoordinateSpan(latitudeDelta: 0.15, longitudeDelta: 0.15))
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

you can also check this URL for more info about other useful features added to SwiftUI2.您还可以查看此URL以获取有关添加到 SwiftUI2 的其他有用功能的更多信息。

import SwiftUI
import MapKit

struct ContentView: View {
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: -23.506403, longitude: -46.1509555),
        span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))

    var body: some View {
        Map(coordinateRegion: $region, showsUserLocation: true)
    }
}

Available for XCode 12 .适用于XCode 12

import SwiftUI
import MapKit

struct ContentView: View {
    
    @State private var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 37.321127, longitude: -122.047790),
        span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
    
    var body: some View {
        Map(coordinateRegion: $region)
    }
}

Using this you can find users region使用这个你可以找到用户区域

Text(Locale.current.localizedString(forRegionCode: Locale.current.regionCode!) ?? "")
                    .font(.system(size: 30))
                    .fontWeight(.bold)

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

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