SwiftUI с картой MKMapView не обновляется после изменений - PullRequest
0 голосов
/ 20 марта 2020

У меня есть приложение 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

...