【问题标题】:What is the proper way of adding a "show user location" button for an MKMapView in SwiftUI?在 SwiftUI 中为 MKMapView 添加“显示用户位置”按钮的正确方法是什么?
【发布时间】:2019-09-27 02:07:55
【问题描述】:

我正在尝试使用 MKMapView 和一个按钮来创建一个 SwiftUI 视图以导航到用户位置。以下是我的全部代码。我创建了一个名为MapView 的视图,它符合UIViewRepresentable 来保存我的MKMapView。我有一个位置按钮,点击时将shouldNavigateToUserLocation 设置为true。这会导致 UI 重新加载,如果 shouldNavigateToUserLocation 为真,我的 MapView 会导航到用户位置。然后,它将shouldNavigateToUserLocation 设置为 false,这样 MapView 就不会在状态发生变化时不断移动到用户位置。

这种方法在真实设备上运行时似乎有效,但我收到警告“在视图更新期间修改状态,这将导致未定义的行为。”在第 87 行,即shouldNavigateToUserLocation = false。这是可以理解的,但我的问题是,我怎样才能避免这种情况?我似乎找不到重组代码的方法,因此我没有违反在视图更新期间不修改状态的规则,同时当且仅当用户按下按钮时,地图仍会导航到用户位置。

我尝试了几种不同的方法,但我主要遇到的问题是我的 MapView 和我的 Controller 类实际上都没有直接访问 MKMapView。我理解为什么在 SwiftUI 中会这样,但它确实限制了我的能力。

这是我的全部代码:

import SwiftUI
import MapKit

struct ContentView: View {

  @State var currentlyDisplayingLocationAuthorizationRequest = false
  @State var shouldNavigateToUserLocation = false

  let locationManager = CLLocationManager()

  var body: some View {
    ZStack {
      MapView(currentlyDisplayingLocationAuthorizationRequest: $currentlyDisplayingLocationAuthorizationRequest,
              shouldNavigateToUserLocation: $shouldNavigateToUserLocation)

      HStack {
        Spacer()
        VStack {
          Spacer()
          Button(action: {
            self.checkForLocationAuthorizationAndNavigateToUserLocation()
          }) {
            Image(systemName: "location")
              .imageScale(.large)
              .accessibility(label: Text("Locate Me"))
              .padding()
          }
          .background(Color.gray)
          .cornerRadius(10)
          .padding()
        }
      }
    }
    .onAppear {
      self.shouldNavigateToUserLocation = true
    }
  }

  func checkForLocationAuthorizationAndNavigateToUserLocation() {
    currentlyDisplayingLocationAuthorizationRequest = false

    if CLLocationManager.authorizationStatus() == .notDetermined {
      print("location authorization not determined")
      currentlyDisplayingLocationAuthorizationRequest = true
      locationManager.requestWhenInUseAuthorization()
      return
    }

    shouldNavigateToUserLocation = true
  }

}

struct MapView: UIViewRepresentable {

  @Binding var currentlyDisplayingLocationAuthorizationRequest: Bool
  @Binding var shouldNavigateToUserLocation: Bool

  let locationManager = CLLocationManager()

  func makeUIView(context: Context) -> MKMapView {
    let map = MKMapView()
    map.delegate = context.coordinator
    map.showsUserLocation = true
    return map
  }

  func updateUIView(_ uiView: MKMapView, context: Context) {
    if !currentlyDisplayingLocationAuthorizationRequest && shouldNavigateToUserLocation {
      moveToUserLocation(map: uiView)
    }
  }

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }

  // MARK: Location -

  private func moveToUserLocation(map: MKMapView) {
    guard let location = locationManager.location else { return }

    let region = MKCoordinateRegion(center: location.coordinate,
                                    span: MKCoordinateSpan(latitudeDelta: 0.02,
                                                           longitudeDelta: 0.02))
    map.setRegion(region, animated: true)
    shouldNavigateToUserLocation = false
  }

  // MARK: Coordinator -

  final class Coordinator: NSObject, MKMapViewDelegate {

    var control: MapView

    init(_ control: MapView) {
      self.control = control
    }

  }

}

【问题讨论】:

标签: mkmapview swiftui


【解决方案1】:

这不是您要搜索的内容,但您应该查看 my recent answer 到另一个相关问题 (How to add a move back to user location button in swiftUI?)。我认为它可以帮助您或其他面临同样问题的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-29
    • 2011-01-05
    • 2011-11-14
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多