从UIViewRepresentable内部推送SwiftUI视图

时间:2020-08-24 20:04:32

标签: swiftui

我创建了一个使用MKMapView的MapView,地图显示OK,所有注释图钉都显示OK,我可以点击图钉以获取其他信息,然后在我点击其他信息时将其推送到另一个SwiftUI视图。我看不到如何从UIViewRepresentable内部推送SwiftUi视图。 MapView的代码如下,即使我调用MapView时,navigationController始终为nil,它位于NavigationView中。

import SwiftUI
import MapKit

class MapAnnotationItem: NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D
    var title: String?
    var subtitle: String?
    var item: Any?
    
    init(coordinate: CLLocationCoordinate2D) {
        self.coordinate = coordinate
    }
}

struct MapViewRepresentable : UIViewRepresentable {
    @Binding var coordinateRegion: MKCoordinateRegion
    @Binding var annotationItems: [MapAnnotationItem]
    @State var mapView = MKMapView()
    @State var showReport = false
    var viewController: UIHostingController<MapView>
    
    func makeUIView(context: UIViewRepresentableContext<MapViewRepresentable>) -> MKMapView {
        mapView.delegate = context.coordinator
        mapView.showsUserLocation = false
        mapView.region = coordinateRegion
        mapView.addAnnotations(annotationItems)
        return mapView
    }

    func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapViewRepresentable>) {
        uiView.region = coordinateRegion
        let allAnnotations = uiView.annotations
        uiView.removeAnnotations(allAnnotations)
        uiView.addAnnotations(annotationItems)
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(viewController: viewController)
    }

    class Coordinator: NSObject, MKMapViewDelegate {
        var tappedItem: Any?
        var viewController: UIHostingController<MapView>
        
        init(viewController: UIHostingController<MapView>) {
            self.viewController = viewController
        }

        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            var annotationView: MKPinAnnotationView?
            if (annotation is MKUserLocation) == true {
                annotationView = nil
            } else {
                annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "MapAnnotation")
                tappedItem = (annotation as? MapAnnotationItem)?.item
                if (tappedItem is Report) {
                    annotationView?.pinTintColor = MKPinAnnotationView.redPinColor()
                } else if (tappedItem is User) {
                    annotationView?.image = UIImage(named: "MapPinIcon\(AppSettings.shared.appNameNoSpaces)")
                }
                annotationView?.animatesDrop = false
                annotationView?.canShowCallout = true
                annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
            }
            return annotationView
        }
        
        func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
            tappedItem = (view.annotation as? MapAnnotationItem)?.item
            if (tappedItem is Report) {
                let viewControllerReport = UIHostingController(rootView: ReportView(report: tappedItem as! Report))
                print(viewController.navigationController) // This is nil
                viewController.navigationController?.pushViewController(viewControllerReport, animated: true)
            } else if (tappedItem is User) {
                // FIXME: Push to user
            }
        }
    }
}


struct MapView: View {
    @Binding var coordinateRegion: MKCoordinateRegion
    @Binding var annotationItems: [MapAnnotationItem]
    var navigationTitle: String
    @State private var displayAnnotationText = false
    
    var body: some View {
        Print(annotationItems.count)
        MapViewRepresentable(coordinateRegion: $coordinateRegion, annotationItems: $annotationItems, viewController: UIHostingController(rootView: self))
            .navigationTitle(navigationTitle)
    }
}

1 个答案:

答案 0 :(得分:0)

不确定这是最好的解决方案,但是我设法通过替换来使其起作用:

viewController.navigationController?.pushViewController(viewControllerReport, animated: true)

具有:

mapView.parentViewController?.navigationController?.pushViewController(viewControllerReport, animated: true)

并添加:

extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder?.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}