11

我正在使用 SwiftUI 显示地图,如果用户点击注释,它会在 VStack 中弹出一个详细视图。我已经制作了地图视图并在另一个 SwiftUI 文件中插入了注释。我还做了详细视图。

如何在主视图文件中访问该地图的注释以定义 .tapaction 以便他们将其用于详细视图?

我尝试将视图定义为 MKMapView,但无法为另一个 SwiftUI 视图中的 UIViewRepresentable 执行此操作。

主视图(ContentView)代码为:

struct ContentView: View {
    @State private var chosen = false

    var body: some View {

        VStack {
            MapView()
            .edgesIgnoringSafeArea(.top)
            .frame(height: chosen ? 600:nil)
            .tapAction {
            withAnimation{ self.chosen.toggle()}
            }

    if chosen {
        ExtractedView()
            }
        }
    }
}

地图视图代码是:

struct MapView : UIViewRepresentable {
    @State private var userLocationIsEnabled = false
    var locationManager = CLLocationManager()
    func makeUIView(context: Context) -> MKMapView {
    MKMapView(frame: .zero)

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

        view.showsUserLocation = true

        .
        .
        .

            let sampleCoordinates = [
                CLLocation(latitude: xx.xxx, longitude: xx.xxx),
                CLLocation(latitude: xx.xxx, longitude: xx.xxx),
                CLLocation(latitude: xx.xxx, longitude: xx.xxx)
                ]
            addAnnotations(coords: sampleCoordinates, view: view)

        }
    }

}

我希望能够访问地图视图注释并在另一个视图中定义点击操作。

4

1 回答 1

15

在 SwiftUI DSL 中,您不能访问视图。

相反,您可以组合它们的“表示”来创建视图。

一个大头针可以用一个对象来表示——操作大头针也会更新地图。

这是我们的 pin 对象:

class MapPin: NSObject, MKAnnotation {

    let coordinate: CLLocationCoordinate2D
    let title: String?
    let subtitle: String?
    let action: (() -> Void)?

    init(coordinate: CLLocationCoordinate2D,
         title: String? = nil,
         subtitle: String? = nil,
         action: (() -> Void)? = nil) {
        self.coordinate = coordinate
        self.title = title
        self.subtitle = subtitle
        self.action = action
    }

}

Here's my Map,它不仅是UIViewRepresentable,而且还使用了Coordinator.

(更多关于UIViewRepresentable和协调者可以在优秀的 WWDC 2019 演讲中找到 -集成 SwiftUI

struct Map : UIViewRepresentable {

    class Coordinator: NSObject, MKMapViewDelegate {

        @Binding var selectedPin: MapPin?

        init(selectedPin: Binding<MapPin?>) {
            _selectedPin = selectedPin
        }

        func mapView(_ mapView: MKMapView,
                     didSelect view: MKAnnotationView) {
            guard let pin = view.annotation as? MapPin else {
                return
            }
            pin.action?()
            selectedPin = pin
        }

        func mapView(_ mapView: MKMapView, didDeselect view: MKAnnotationView) {
            guard (view.annotation as? MapPin) != nil else {
                return
            }
            selectedPin = nil
        }
    }

    @Binding var pins: [MapPin]
    @Binding var selectedPin: MapPin?

    func makeCoordinator() -> Coordinator {
        return Coordinator(selectedPin: $selectedPin)
    }

    func makeUIView(context: Context) -> MKMapView {
        let view = MKMapView(frame: .zero)
        view.delegate = context.coordinator
        return view
    }

    func updateUIView(_ uiView: MKMapView, context: Context) {

        uiView.removeAnnotations(uiView.annotations)
        uiView.addAnnotations(pins)
        if let selectedPin = selectedPin {
            uiView.selectAnnotation(selectedPin, animated: false)
        }

    }

}

这个想法是:

  • 引脚位于@State包含地图的视图上,并作为绑定向下传递。
  • 每次添加或删除 pin 时,都会触发 UI 更新 - 所有 pin 都将被删除,然后再次添加(效率不是很高,但这超出了此答案的范围)
  • Coordinator是地图委托 - 我可以MapPin从委托方法中检索触摸。

测试它

struct ContentView: View {

    @State var pins: [MapPin] = [
        MapPin(coordinate: CLLocationCoordinate2D(latitude: 51.509865,
                                                  longitude: -0.118092),
               title: "London",
               subtitle: "Big Smoke",
               action: { print("Hey mate!") } )
    ]
    @State var selectedPin: MapPin?

    var body: some View {
        NavigationView {
            VStack {
                Map(pins: $pins, selectedPin: $selectedPin)
                    .frame(width: 300, height: 300)
                if selectedPin != nil {
                    Text(verbatim: "Welcome to \(selectedPin?.title ?? "???")!")
                }
            }
        }

    }

}

...并尝试在英国伦敦缩放/点击图钉 :)

在此处输入图像描述

于 2019-06-12T14:18:45.133 回答