如何使 SwiftUi 中的按钮触发 UIKit 包装器中的函数?

发布于 2025-01-14 14:57:24 字数 1641 浏览 1 评论 0原文

我可以通过长按手势将 MKPointAnnotations 添加到我的 Mapkit MapView。

现在我想通过按 Swift UI 中的按钮来删除这些标记。

我的想法是在按下按钮时设置一个变量 true 并使用该变量作为 updateUIView 函数中函数的条件。但我收到错误消息,指出我无法在此嵌套函数中引用此变量。

这是我的 addAnnotations 包装器中的一个片段。效果很好。如何在我的mapView上实现removeAnnotation函数?

func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.setRegion(region, animated: false)
        map.showsUserLocation = true
    
    map.delegate = context.coordinator
    locationManager.delegate = context.coordinator
    
    
    let longPress = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.addAnnotation(gesture:)))
    longPress.minimumPressDuration = 1
    map.addGestureRecognizer(longPress)
    
    
    return map
}


class Coordinator: NSObject, MKMapViewDelegate, CLLocationManagerDelegate {
    
    var mapView: MapView
    init(mapView: MapView) {            
        self.mapView = mapView      
    }
     
    @objc func addAnnotation(gesture: UIGestureRecognizer) {
        
        if gesture.state == .ended {
            
            
            if let mapView = gesture.view as? MKMapView {
                let point = gesture.location(in: mapView)
                let locationCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
                let myPin = MKPointAnnotation()
                myPin.title = "Latitude: \(locationCoordinate.latitude), Longitude: \(locationCoordinate.longitude)"
                myPin.coordinate = locationCoordinate
                mapView.addAnnotation(myPin)
            }
        }
    }

          

I can add MKPointAnnotations by Long Tap Gesture to my Mapkit MapView.

Now I want to remove those markers by pressing a Button in Swift UI.

My idea was to set a variable true when the button is pressed and use this variable as condition for a function in the updateUIView function. But I get the error message that i can't refer to this variable in this nested function.

Here's a snippet from my addAnnotations wrapper. It works fine. How can I implement the removeAnnotation function on my mapView?

func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.setRegion(region, animated: false)
        map.showsUserLocation = true
    
    map.delegate = context.coordinator
    locationManager.delegate = context.coordinator
    
    
    let longPress = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.addAnnotation(gesture:)))
    longPress.minimumPressDuration = 1
    map.addGestureRecognizer(longPress)
    
    
    return map
}


class Coordinator: NSObject, MKMapViewDelegate, CLLocationManagerDelegate {
    
    var mapView: MapView
    init(mapView: MapView) {            
        self.mapView = mapView      
    }
     
    @objc func addAnnotation(gesture: UIGestureRecognizer) {
        
        if gesture.state == .ended {
            
            
            if let mapView = gesture.view as? MKMapView {
                let point = gesture.location(in: mapView)
                let locationCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
                let myPin = MKPointAnnotation()
                myPin.title = "Latitude: \(locationCoordinate.latitude), Longitude: \(locationCoordinate.longitude)"
                myPin.coordinate = locationCoordinate
                mapView.addAnnotation(myPin)
            }
        }
    }

          

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你没皮卡萌 2025-01-21 14:57:24

首先,我不知道为什么你选择在 SwiftUI 项目中使用 MapKit 和 UIKit,我假设,除非你打算支持 iOS 13,否则你可以在 SwiftUI 中完成这一切,但无论如何,这就是你如何做到这一点:

你有你的导入当然:

import SwiftUI
import CoreLocation
import MapKit

然后像这样创建一个viewModel:

class MapViewModel: ObservableObject {
    
    @Published var didPressButton = false
    
}

添加一个@StateObject属性包装器(如果您在ContentView中创建实例,请避免使用@ObservedObject)

是的,您也可以使用@EnvironmentObject

struct ContentView: View {
    
    @StateObject var viewModel = MapViewModel()
    
    var body: some View {
        ZStack {
            MapView(viewModel: viewModel)
            Button("Perform Action") {
            
                viewModel.didPressButton.toggle()
            }
        }
    }
}

然后创建一个@ObservableObject 它将与 ContentView 共享 MapViewModel 的相同实例

struct MapView: UIViewRepresentable {

    @ObservableObject var viewModel: MapViewModel

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        if viewModel.didPressButton == true {
            context.coordinator.performActionFromSwiftUI()
        }
    }
    
    func makeUIView(context: Context) -> MKMapView {
        let map = context.coordinator.mapView
        map.setRegion(region, animated: false)
        map.showsUserLocation = true
        
        map.delegate = context.coordinator
        locationManager.delegate = context.coordinator
        
        
        let longPress = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.addAnnotation(gesture:)))
        longPress.minimumPressDuration = 1
        map.addGestureRecognizer(longPress)
        
        
        return map
    }
    
}

在 Coordinator 类中,添加将在 UIViewRepresentable updateUIView 方法中调用的函数。

  • 我还建议在 UIViewRepresentable 结构中的 makeUIView 方法中返回 mapView 时,返回 context.coordinator.mapView 而不是在那里创建实例。

class Coordinator: NSObject, MKMapViewDelegate, CLLocationManagerDelegate {
    
    var mapView = MKMapView()
    
    
    func performActionFromSwiftUI() {
        
        print("tapped")
    }
    
    @objc func addAnnotation(gesture: UIGestureRecognizer) {
        
        if gesture.state == .ended {
            
            
            if let mapView = gesture.view as? MKMapView {
                let point = gesture.location(in: mapView)
                let locationCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
                let myPin = MKPointAnnotation()
                myPin.title = "Latitude: \(locationCoordinate.latitude), Longitude: \(locationCoordinate.longitude)"
                myPin.coordinate = locationCoordinate
                mapView.addAnnotation(myPin)
            }
        }
    }
}

Firstly, I don't know why you chose to use MapKit with UIKit in a SwiftUI project I assume, when you can do it all in SwiftUI unless you intend to support iOS 13 but anyways here is how you do it:

You have your imports of course:

import SwiftUI
import CoreLocation
import MapKit

Then create a viewModel like so:

class MapViewModel: ObservableObject {
    
    @Published var didPressButton = false
    
}

Add an @StateObject property wrapper(avoid using @ObservevedObject if you are creating the instance in your ContentView)

And yes you can also use @EnvironmentObject

struct ContentView: View {
    
    @StateObject var viewModel = MapViewModel()
    
    var body: some View {
        ZStack {
            MapView(viewModel: viewModel)
            Button("Perform Action") {
            
                viewModel.didPressButton.toggle()
            }
        }
    }
}

Then create an @ObservableObject which will share the same instance of MapViewModel from your ContentView

struct MapView: UIViewRepresentable {

    @ObservableObject var viewModel: MapViewModel

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        if viewModel.didPressButton == true {
            context.coordinator.performActionFromSwiftUI()
        }
    }
    
    func makeUIView(context: Context) -> MKMapView {
        let map = context.coordinator.mapView
        map.setRegion(region, animated: false)
        map.showsUserLocation = true
        
        map.delegate = context.coordinator
        locationManager.delegate = context.coordinator
        
        
        let longPress = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.addAnnotation(gesture:)))
        longPress.minimumPressDuration = 1
        map.addGestureRecognizer(longPress)
        
        
        return map
    }
    
}

In your Coordinator class, add the function which will be called in your UIViewRepresentable updateUIView method.

  • I also suggest when returning a mapView in the makeUIView method in your UIViewRepresentable struct, return the context.coordinator.mapView rather than creating an instance there.

class Coordinator: NSObject, MKMapViewDelegate, CLLocationManagerDelegate {
    
    var mapView = MKMapView()
    
    
    func performActionFromSwiftUI() {
        
        print("tapped")
    }
    
    @objc func addAnnotation(gesture: UIGestureRecognizer) {
        
        if gesture.state == .ended {
            
            
            if let mapView = gesture.view as? MKMapView {
                let point = gesture.location(in: mapView)
                let locationCoordinate = mapView.convert(point, toCoordinateFrom: mapView)
                let myPin = MKPointAnnotation()
                myPin.title = "Latitude: \(locationCoordinate.latitude), Longitude: \(locationCoordinate.longitude)"
                myPin.coordinate = locationCoordinate
                mapView.addAnnotation(myPin)
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文