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
Displaying a Map View in SwiftUI To work with Map , you need to provide a binding of MKCoordinateRegion that keeps track of the region to display on the map. The MKCoordinateRegion structure lets you specify a rectangular geographic region centered around a specific latitude and longitude.
MapKit is a powerful API available on iOS devices that makes it easy to display maps, mark locations, enhance with custom data and even draw routes or other shapes on top.
The width and height of a map region.
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)
}
}
}
}
}
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
Screenshot with explanation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With