SwiftUI MapKit UIViewRepresentable无法显示警报

问题描述 投票:1回答:2

我有一个SwiftUI应用,其中一些视图是使用以下工具制作的MapKit地图UIViewRepresentable。我对兴趣点和用途有自定义注释左右标注按钮都可以执行进一步操作。在右边我只是想要显示有关航路点的信息。在左侧,我想发出警报选择其他操作-例如,插入新的注释点。之前SwiftUI我刚刚发出警报,并且完成了上述两项操作。但据我所知,在UIViewRepresentable版本上没有self.present。因此我没有去过能够显示警报。

只是一个实验-我在SwiftUI视图上附加了SwiftUI警报代码,调用MapView。使用Observable布尔值,我确实可以同时发出这两个警报。这对我来说似乎很奇怪,但是也许警报代码绑定到了全局属性可以是任何地方。

我的第一次尝试:(该结构为DetailMapView)

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

    if control == view.leftCalloutAccessoryView {
        guard let tappedLocationCoord = view.annotation?.coordinate else {return}
        let tappedLocation = CLLocation(latitude: tappedLocationCoord.latitude, longitude: tappedLocationCoord.longitude)

        let ac = UIAlertController(title: nil, message: nil, preferredStyle: .alert)

        let deleteAction = UIAlertAction(title: "Delete Waypoint", style: .destructive) { (action) in
            //some stuff
        }

        let insertAction = UIAlertAction(title: "Insert Waypoint After This", style: .default) { (action) in
            //some stuff
        }

        let cancelAction = UIAlertAction(title: "Cancel", style: .default) { (action) in
            //some stuff
        }//cancelAction

        ac.addAction(deleteAction)
        ac.addAction(insertAction)
        ac.addAction(cancelAction)

        //tried adding self, referencing parent - always error saying
        //the object does not have a .present
        mapView.present(ac, animated: true)

    } else if control == view.rightCalloutAccessoryView {
        //more of the same
    }
}//annotationView

然后我删除了警报代码并添加了:

parent.userDefaultsManager.shouldShowAnnotationEditMenu.toggle()

并且我将呼叫屏幕更改为:

@ObservedObject var userDefaultsManager: UserDefaultsManager
var aTrip: Trip?

var body: some View {

    VStack {
        Text(aTrip?.name ?? "Unknown Map Name")
            .padding(.top, -50)
            .padding(.bottom, -20)

        DetailMapView(aTrip: aTrip, userDefaultsManager: userDefaultsManager)
            .padding(.top, -20)
            .alert(isPresented: $userDefaultsManager.shouldShowAddress) {
                //Alert(title: Text("\(aTrip?.name ?? "No") Address"),
                Alert(title: Text(self.userDefaultsManager.approximateAddress),
                      message: Text("This is the approximate street address."),
                      dismissButton: .default(Text("Got it!")))
            }//.alert shouldShowAddress

        Text("This is the view where the trip information will be displayed.")
            .multilineTextAlignment(.center)
        .alert(isPresented: $userDefaultsManager.shouldShowAnnotationEditMenu) {
            Alert(title: Text("Edit Annotations"),
                  message: Text("Choose this to insert an Annotation."),
                  dismissButton: .default(Text("Got it!")))
        }//.alert shouldShowAddress
    }
}

我猜这是否安全,我可以使它起作用-但看起来似乎比较复杂应该。

这是主意:

enter image description here

任何指导将不胜感激:Xcode版本11.3.1(11C504)

ios xcode mapkit swiftui uiviewrepresentable
2个回答
1
投票
一种执行所需操作的方法是使用Bool@State@Binding)。

您还需要一个View,而不是直接在UIViewRepresentable中使用您的SceneDelegate。因为这是链接alert的位置。

例如:

struct MainView: View { @State var text = "" @State var showingAlert: Bool var body: some View { VStack { MapView(showingAlert: self.$showingAlert) .alert(isPresented: $showingAlert) { () -> Alert in print("SHOWING ALERT BODY: --> \($showingAlert.wrappedValue)") return Alert(title: Text("Important message"), message: Text("Go out and have a girlfriend!"), dismissButton: .default(Text("Got it!"))) } } } }

然后您的

MapView应该像这样:

struct MapView: UIViewRepresentable { let landmarks = LandmarkAnnotation.requestMockData() @Binding var showingAlert: Bool func makeCoordinator() -> MapViewCoordinator { MapViewCoordinator(mapView: self, showingAlert: self.$showingAlert) } /** - Description - Replace the body with a make UIView(context:) method that creates and return an empty MKMapView */ func makeUIView(context: Context) -> MKMapView { MKMapView(frame: .zero) } func updateUIView(_ view: MKMapView, context: Context){ //If you changing the Map Annotation then you have to remove old Annotations //mapView.removeAnnotations(mapView.annotations) view.delegate = context.coordinator view.addAnnotations(landmarks) } } struct MapView_Previews: PreviewProvider { static var previews: some View { MapView(showingAlert: Binding<Bool>.constant(true)) } }

最后,在您的MapViewCoordinator中(我想您有这个类,它是实现MKMapViewDelegate的委托方法的类。)。
/*
 Coordinator for using UIKit inside SwiftUI.
 */
class MapViewCoordinator: NSObject, MKMapViewDelegate {

    var mapViewController: MapView!
    @Binding var showAlert: Bool

    init(mapView: MapView, showingAlert: Binding<Bool>) {

        self.mapViewController = mapView
        self._showAlert = showingAlert
        super.init()
    }

    func mapView(_ mapView: MKMapView, viewFor
        annotation: MKAnnotation) -> MKAnnotationView?{
        //Custom View for Annotation
        let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "customView")
        annotationView.canShowCallout = true
        //Your custom image icon
        annotationView.image = UIImage(named: "locationPin")
        return annotationView
    }

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

    func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
        print("didSelect")

        self.showAlert = true
    }
}

如您所见,我只是利用Bool标志。特别是@Binding

enter image description here

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.