Я пытаюсь создать представление SwiftUI с MKMapView и кнопкой, чтобы перейти к местоположению пользователя.Ниже приведен весь мой код.Я создал представление с именем MapView
, которое соответствует UIViewRepresentable
для хранения моего MKMapView.У меня есть кнопка местоположения, которая при нажатии устанавливает shouldNavigateToUserLocation
в значение true.Это приводит к перезагрузке пользовательского интерфейса, и мой MapView
перемещается в местоположение пользователя, если значение shouldNavigateToUserLocation
равно true.Затем он устанавливает 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
}
}
}