Reputation: 81
I have a map in a view that is centered on Chicago. I want the user to be able to place a pin/annotation on the map and then retrieve those coordinates. The map loads Chicago fine but I can't get the annotation code to work.
I can't seem to find an answer for SwiftUI, specifically. Only Swift and Storyboards. I feel like I have 99% of the code but the pieces aren't in the right spots. I included a screen shot of where the errors are. Thanks for your help.
import SwiftUI
import MapKit
struct EntireMapView: UIViewRepresentable {
func updateUIView(_ mapView: MKMapView, context: Context) {
mapView.delegate = context.coordinator
let longPressGesture = UILongPressGestureRecognizer(target: mapView, action: #selector(EntireMapViewCoordinator.addAnnotation(gesture:)))
mapView.addGestureRecognizer(longPressGesture)
let span = MKCoordinateSpan(latitudeDelta: 0.3, longitudeDelta: 0.3)
var chicagoCoordinate = CLLocationCoordinate2D()
chicagoCoordinate.latitude = 41.878113
chicagoCoordinate.longitude = -87.629799
let region = MKCoordinateRegion(center: chicagoCoordinate, span: span)
mapView.setRegion(region, animated: true)
}
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView(frame: .zero)
mapView.delegate = context.coordinator
return mapView
}
func makeCoordinator() -> EntireMapViewCoordinator {
return EntireMapViewCoordinator(self)
}
class EntireMapViewCoordinator: NSObject, MKMapViewDelegate {
var entireMapViewController: EntireMapView
init(_ control: EntireMapView) {
self.entireMapViewController = control
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
return (annotation as? MKAnnotationView)!
}
@objc func addAnnotation(gesture: UILongPressGestureRecognizer) {
if gesture.state == .ended {
let point = gesture.location(in: self.mapView) **<--- ERROR HERE**
let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
var annotation = MKPointAnnotation()
annotation.coordinate = coordinate
self.mapView.addAnnotation(annotation) **<--- ERROR HERE**
}
}
}
}
struct EntireMapView_Previews: PreviewProvider {
static var previews: some View {
EntireMapView()
}
}
Here's a screen shot of the errors
Upvotes: 8
Views: 2510
Reputation: 3631
Here is a complete code for the answer. The credit goes mostly to @yeezy , because obtaining view with this line: let mapView = gestureRecognizer.view as? MKMApView
was the main mistake in the question.
struct EntireMapView: UIViewRepresentable {
func updateUIView(_ mapView: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 0.3, longitudeDelta: 0.3)
var chicagoCoordinate = CLLocationCoordinate2D()
chicagoCoordinate.latitude = 41.878113
chicagoCoordinate.longitude = -87.629799
let region = MKCoordinateRegion(center: chicagoCoordinate, span: span)
mapView.setRegion(region, animated: true)
}
func makeUIView(context: Context) -> MKMapView {
let myMap = MKMapView(frame: .zero)
let longPress = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(EntireMapViewCoordinator.addAnnotation(gesture:)))
longPress.minimumPressDuration = 1
myMap.addGestureRecognizer(longPress)
myMap.delegate = context.coordinator
return myMap
}
func makeCoordinator() -> EntireMapViewCoordinator {
return EntireMapViewCoordinator(self)
}
class EntireMapViewCoordinator: NSObject, MKMapViewDelegate {
var entireMapViewController: EntireMapView
init(_ control: EntireMapView) {
self.entireMapViewController = control
}
@objc func addAnnotation(gesture: UIGestureRecognizer) {
if gesture.state == .ended {
if let mapView = gesture.view as? MKMapView {
let point = gesture.location(in: mapView)
let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
mapView.addAnnotation(annotation)
}
}
}
}
}
Upvotes: 5
Reputation: 11
i don't know if you are still looking for an answer. But here is one. I struggled with this problem a lot and i don't know if my answer is correct but it works for me so here it is:
@objc func addAnnotation(gesture: UITapGestureRecognizer){
if let mapView = gestureRecognizer.view as? MKMApView{
let point = gestureRecognizer.location(in: mapView)
let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
DispatchQueue.main.async{
mapView.addAnnotation(annotation)
}
}
}
as you can see i am not using an UILongPressGestureRecognizer but rather an UITapGestureRecognize and i took your idea of using the gestureRecognizers view.
Disclaimer: I don't know if this is the best way to do it! I just started swift/swiftUI programming half a year ago :) and this is my first answer.
For further implementation: You should prolly just collect all the annotations in an array and update the mapView from within the updateUIView method. I dont know if i am correct when using the DispatchQueue.main.async here. But whenever i come across changes of the Ui i think you should do it on the main thread
Upvotes: 1
Reputation: 552
I would start by taking mapView.delegate = context.coordinator
out of updateUIView. This should be done only once, in makeUIView (which you're already doing).
Upvotes: 0