SwiftUI с картой MKMapView не обновляется после изменений
У меня есть приложение SwiftUI, которое включает MKMapView UIViewRepresentable. Функция карты позволяет пользователю выбирать свой собственный путь, создавая путевые точки. Базовая логика работает отлично, но мне не удалось перерисовать карту при внесении определенных изменений. В частности, пользователь может нажать аннотацию путевой точки для существующей поездки / карты и выбрать добавление новой путевой точки после нажатого элемента или удаление затронутого элемента. Как ни странно, удаление работает так, как ожидалось, но при вставке карта не перерисовывается (равно как и рассчитанное расстояние не обновляется в представлении). Дизайн - это базовый список / деталь, где список - это поездки, а деталь - это mapView для поездки. Данные хранятся в Core Data и действительно обновляются должным образом при удалении или вставке, но, опять же,для вставок карта не обновляется до тех пор, пока эта поездка не будет закрыта, а затем снова открыта.
Для вставки я накладываю на карту представление SwiftUI, которое просто содержит цель (в центре карты) и кнопку для вставки элемента. Пользователь перемещает карту так, чтобы новая путевая точка оказалась под целью, и нажимает кнопку вставки. Я хочу, чтобы карта перерисовывалась после вставки путевой точки (с помощью кнопки).
Я предполагаю, что основы - есть ли способ заставить протокол MKMapKit вызывать func updateUIView(_ view: MKMapView, context: Context) {} Из представления, которое не является UIViewRepresentable, и / или как мне получить ссылку на mapview в файле SwiftUI, который вызывает деталь. Кажется, что обратная привязка должна работать, но мне это не удалось.
Этот файл SwiftUI вызывает DetailMapView, который является UIViewRepresentable. При нажатии на кнопку координаты вставляются в Core Data.
struct ComboDetailMapView: View {
@ObservedObject var udm: UserDefaultsManager
@Environment(\.presentationMode) var presentationMode
@State var thisMap: MKMapView?
let generator = UINotificationFeedbackGenerator()
var aTrip: Trip?
var body: some View {
GeometryReader { geo in
ZStack {
ZStack {
VStack {
Text(self.aTrip?.name ?? "Unknown Map Name")
.padding(.top, -50)
.padding(.bottom, -20)
DetailMapView(udm: self.udm, aTrip: self.aTrip)
.padding(.top, -20)
}//vstack
VStack {
Spacer()
ZStack {
RoundedRectangle(cornerRadius: 20)
.fill(Color.white).opacity(0.8)
.frame(width: geo.size.width - 20, height: 100)
Text(self.udm.tripTimeAndDistance)
//...bunch of modifiers
}
.padding(.bottom, 20)
}//vstack
}//to put time and distance on top
ZStack {
VStack {
Spacer()
HStack {
Spacer()
Button(action: {
self.generator.notificationOccurred(.success)
self.udm.showAddWaypointControls.toggle()
guard let guardTrip = self.aTrip else { return }
DetailMapView(udm: self.udm).insertNewWaypoint(insertTrip: guardTrip, centerCoordinate: self.udm.pubCenterCoordinate, name: "Center", subtitle: "Center", pinText: "Center", wayPointSequence: self.udm.insertSequenceNumber + 1)
}) {
Image(systemName: "plus")
}
//...bunch of modifiers
}
}//vstack
Circle()
//...modifiers
}//button and circle zstack
.offset(x: self.udm.showAddWaypointControls ? 0 : screen.width)
.animation(.easeInOut(duration: 1.0))
}//zstack
}//geo
}//body
}
DetailMapView:
struct DetailMapView: UIViewRepresentable {
let kAppDelegate = UIApplication.shared.delegate as! AppDelegate
@Environment(\.presentationMode) var presentationMode
@ObservedObject var udm: UserDefaultsManager
//bunch of @State variables
var aTrip: Trip?
class Coordinator: NSObject, MKMapViewDelegate {
var parent: DetailMapView
init(_ parent: DetailMapView) {
self.parent = parent
}
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
parent.udm.pubCenterCoordinate = mapView.centerCoordinate
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "CRSAnnotationView"
//...more code - all this works
return crsAnnotationView
}//viewfor
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.leftCalloutAccessoryView {
//...more code - all this works
} else if control == view.rightCalloutAccessoryView {
mapView.removeAnnotations(parent.annotations)
parent.annotations = []
//this displays the overlay with the target and the button to add the waypoint
parent.udm.showAddWaypointControls.toggle()
guard let guardTrip = parent.aTrip else { return }
for wp in guardTrip.waypoints {
//...code to sequence the waypoints in the Core Data NSSet - this all works
}//for wp in parent.aTrip!.waypoints
}//else if control == else if control
}//annotationView
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(polyline: overlay as! MKPolyline)
renderer.strokeColor = UIColor.blue
renderer.lineWidth = 4.0
return renderer
}//rendererFor
}//class coordinator
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> MKMapView {
//...housekeeping code for distance and time display - all works
self.udm.showAddWaypointControls = false
let mapView = MKMapView()
mapView.showsUserLocation = true
mapView.delegate = context.coordinator
udm.tripTimeAndDistance = "Calculating..."
return mapView
}
//This is called for deletions, but not for insertions:
func updateUIView(_ view: MKMapView, context: Context) {
redrawTheMap(trip: aTrip, mapView: view)
}//updateUIView
func doOneWaypointPolylineCallback(view: MKMapView, source: CLLocationCoordinate2D, destination: CLLocationCoordinate2D, callback: @escaping (Double, Double) -> Void) {
//this code gets distance and time for each segment and works
}//doOneWaypointPolylineCallback
func modifyTheWaypointList(trip: Trip?, mapView: MKMapView, view: MKAnnotationView) {
//this code deleted the waypoint from Core Data and works
}//modifyWayList
func redrawTheMap(trip: Trip?, mapView: MKMapView) {
//...this code cycles through the waypoints to add annotations and overlays - it works
}//redrawTheMap
}//struct DetailMapView
Любое руководство будет оценено.
Xcode версии 11.3.1 (11C504