У меня есть приложение SwiftUI, которое включает в себя MKMapView UIViewRepresentable. Функция карты позволяет пользователю выбирать собственный путь, создавая путевые точки. Базовая логика c прекрасно работает, но мне не удалось перерисовать карту при внесении определенных изменений. В частности, пользователь может нажать на аннотацию путевой точки для существующей поездки / карты и выбрать добавление новой путевой точки после отмеченного элемента или удаление отмеченного элемента. Как ни странно, удаление работает, как и ожидалось, но действие вставки не приводит к перерисовке карты (и вычисленное расстояние не обновляется в представлении). Проект представляет собой базовый c список / деталь, где список - это поездки, а деталь - это mapView для поездки. Данные хранятся в Базовых данных и действительно обновляются должным образом, когда выполняется удаление или вставка, но, опять же, для вставок карта не обновляется до тех пор, пока эта поездка не будет закрыта, а затем вновь открыта.
Для вставки я накладываю карту на представление SwiftUI, которое просто содержит цель (в центре карты) и кнопку для вставки элемента. Пользователь перемещает карту, чтобы новая путевая точка находилась под целью, и нажимает кнопку вставки. Я хочу, чтобы карта была перерисована после вставки путевой точки (с кнопки).
Я предполагаю основы - есть ли способ заставить протокол MKMapKit вызвать fun c updateUIView (_ view: MKMapView, context: Context) {} Из представления, которое не является UIViewRepresentable и / или как получить ссылку на представление карты в файле SwiftUI, который вызывает детализацию. Похоже, обратное связывание должно работать, но я не был успешным.
Этот файл SwiftUI вызывает DetailMapView, который является UIViewRepresentable. Нажатие на кнопку вставляет координаты в базовые данные.
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 Version 11.3.1 (11C504