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

0 ответов

Другие вопросы по тегам