Reputation: 31
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)
}
}
}
Upvotes: 2
Views: 1537
Reputation: 323
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.
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)
}
}
}
}
Upvotes: 2