首页 > 解决方案 > SwiftUI NavigationView NavigationLink 完成回调

问题描述

使用 SwiftUI,我在导航视图中嵌入了一个列表,当用户选择一行时,通过 NavigationLink 创建一个新的地图视图。

在这个新的 Mapview 中,用户可以在地图上添加一个图钉并通过 NavigationTabBar 中的尾随按钮(绿色飞机按钮)选择完成

UI 正在正常工作。我的问题是,在用户在地图上添加了一个图钉后,我想将坐标传递回它的根视图,这样我就可以触发函数调用

item.createLocation(item.id, ***coordinates from callback***)

struct RootView: View {
    @StateObject private var data = Model()
    var body: some View {
        NavigationView{
            List(data.entities) {item in
                NavigationLink(destination:RowView(entity: item.content)){
                    Text("Select this row \(item.id)")
                }
            }.navigationTitle("Long press on the map to add a pin")
            .navigationBarItems(
                trailing:
                    Button(action: {
                        item.createLocation(item.id, selectedLocation),
                        self.isActive = false
                        })
                    }) {
                        Image(systemName: "paperplane.circle.fill")
                            .font(.title)
                            .foregroundColor(.green)
                    })
        }
    }
}

这是子视图(MapView):

var selectedLocation = CLLocationCoordinate2D()

struct RowView: UIViewRepresentable {
    let location: Location
    var locationManager = CLLocationManager()
    let locationHandler = LocationHandler()

    public func makeUIView(context:Context)-> MKMapView{
        let mapView = MKMapView(frame: .zero)
        mapView.delegate = context.coordinator
        let longPressed = UILongPressGestureRecognizer(target: context.coordinator,
                                                       action:#selector(context.coordinator.addPinBasedOnGesture(_:)))
        longPressed.minimumPressDuration = 1.0
        mapView.addGestureRecognizer(longPressed)
        
        return mapView
    }
    
    /**
     * Centers map based on location
     * @param view as MKMapView, the map view
     * @param location as CLLocation, Location data that includes coordinates
     */
    func centerToLocation(_ view:MKMapView, _ location: CLLocation?){
        if let location = location {
            let coordinate = CLLocationCoordinate2D(latitude:location.coordinate.latitude ,longitude: location.coordinate.longitude)
                    view.setRegion(MKCoordinateRegion(center: coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000), animated: true)
        }
    }
    
    func updateUIView(_ view:MKMapView, context:Context){
        if locationHandler.authorized {
            view.showsUserLocation = true
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, MKMapViewDelegate{
        var parent: LocationDetailView
        var annotationCoords:CGPoint = CGPoint(x: 0.0, y: 0.0)

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

        @objc func addPinBasedOnGesture(_ gestureRecognizer:UILongPressGestureRecognizer) {
            let mapview = (gestureRecognizer.view as? MKMapView)
            mapview?.removeAnnotations(mapview!.annotations)
            annotationCoords = gestureRecognizer.location(in: mapview)
            let newCoordinates = mapview?.convert(annotationCoords, toCoordinateFrom: mapview)
            let annotation = MKPointAnnotation()
            guard let _newCoordinates = newCoordinates else { return }
            annotation.coordinate = _newCoordinates
            mapview?.addAnnotation(annotation)
            selectedLocation = _newCoordinates
        }
    }
}

我将地图引脚的坐标保存到变量selectedLocation中,该变量设置为全局变量。

主要问题是当按下时Button(action: { item.createLocation(item.id, selectedLocation))总是item.id不同的并且不会返回item.id所选行的。

在 UIKit 中我会实现一个委托来处理这个问题,但我读到在 SwiftUI 中使用委托并不是最佳实践。

我的问题是,如何从 SwiftUI 中 NavigationView 的第二个孩子触发回调。

标签: swiftxcodeswiftuiswiftui-navigationlinkswiftui-navigationview

解决方案


推荐阅读