在 SwiftUI 中选择注释时显示叠加视图

Display overlay view when selecting annotation in SwiftUI

我正在使用 UIRepresentable 在地图上显示注释,并希望在点击选定的图钉时能够显示视图。

我以前使用 Map() 所以能够使用 .onTapGesture 作为注释,但现在注释是从 UIKit 制作的,我如何将所选项目传递到主视图?

我以前的工作:

var body: some View {
  ZStack {
    Map(region: $region, annotationItems: $model.locations) { location in
      MapPin(coordinate: location.coord)
        .onTapGesture {
          modelData.selectedLocation = location
          modelData.isShowingDetail = true
        }
    }
    if modelData.isShowingDetail {
      DetailView(
        isShowingDetail: $modelData.isShowingDetail,
        location: modelData.selectedLocation!
      )
    }
  }
}

现在我有了 UIViewRepresentable:

struct UIMapView: UIViewRepresentable {

  // default setup - coordinator, makeUI, updateUI

  class Coordinator: NSObject, MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
      // how to trigger the overlay??
    }
  }
}

任何帮助将不胜感激,因为我非常坚持这一点:)

在您的 class Coordinator: NSObject, MKMapViewDelegate {...} 中,您可以访问以下功能:

 func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
 ...
 }


func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { 
...
}
    

使用这些(和其他)来做你想做的事。

您想知道在 SwiftUI 视图中选择的注释。所以你必须把它存放在某个地方。声明一个 @State :

struct ContentView: View {
    let locations: [MKAnnotation]
    @State private var selectedLocation: MKAnnotation?
    var body: some View {
            // ... //
    }
}

现在在您的包装器 (UIViewRepresentable) 中,您必须与此 MKAnnotation? 进行绑定:

struct MapView: UIViewRepresentable {
    @Binding var selectedLocation: MKAnnotation?    // HERE
    let annotations: [MKAnnotation]

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.region = // .... //
        mapView.addAnnotations(annotations)
        mapView.delegate = context.coordinator
        return mapView
    }

    func updateUIView(_ view: MKMapView, context: Context) {
        // .... //
    }

现在您应该可以在您的委托(协调器)中访问此变量。为此,您必须将 UIViewRepresentable 传递给协调器:

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView

        init(_ parent: MapView) {
            self.parent = parent
        }

最后,在 func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) 中,您可以在 parent.selectedLocation 中复制 MKAnnotation。 使用 @Binding 这个 MKAnnotation 现在可以在您的父视图 (ContentView) 中访问。您可以在 DetailView.

中显示其属性
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            // ... //
        }
        
        func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
            parent.selectedLocation = view.annotation
        }
    }
}

例如:

struct ContentView: View {
    let locations: [MKAnnotation]
    @State private var selectedLocation: MKAnnotation?
    var body: some View {
        VStack {
            Text("\(selectedLocation?.coordinate.latitude ?? 0)")

            // Don't forget the Binding : $selectedLocation

            MapView(selectedLocation: $selectedLocation, annotations: locations)
        }
    }
}