Reputation:
In short, my current code displays annotations with custom images that it gets from another struct, and when the user clicks on an annotation, it brings up another view.
This is my code:
struct MapView: UIViewRepresentable {
let annotations: [MKPointAnnotation]
@Binding var showUserView: Bool
func makeUIView(context: Context) -> MKMapView {
let mapView = MKMapView(frame: .zero)
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
mapView.userTrackingMode = .followWithHeading
mapView.mapType = .hybridFlyover
let region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 0, longitude: 0),
span: MKCoordinateSpan(latitudeDelta: 180, longitudeDelta: 360))
mapView.setRegion(region, animated: false)
mapView.showsBuildings = true
mapView.addAnnotations(annotations)
// Add gesture recognizer to handle annotation taps
let gestureRecognizer = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.annotationTapped))
mapView.addGestureRecognizer(gestureRecognizer)
return mapView
}
func updateUIView(_ mapView: MKMapView, context: Context) {
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(annotations)
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
class Coordinator: NSObject, MKMapViewDelegate {
let parent: MapView
init( parent: MapView) {
self.parent = parent
}
// Handle annotation taps by toggling showUserView
@objc func annotationTapped() {
parent.showUserView.toggle()
}
func mapView( mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? MKPointAnnotation else {
return nil
}
let identifier = "CustomAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
annotationView?.image = UIImage(named: "first.png")
} else {
annotationView?.annotation = annotation
}
return annotationView
}
}
}
I tried changing the Coordinator struct with the following code, but then nothing in the tap gesture function worked:
class Coordinator: NSObject, MKMapViewDelegate {
let parent: MapView
var selectedAnnotationName: String?
// ... existing code ...
// Handle annotation taps by toggling showUserView and setting the selectedAnnotationName
@objc func annotationTapped(_ sender: UITapGestureRecognizer) {
if let annotationView = sender.view as? MKAnnotationView, let annotation = annotationView.annotation as? MKPointAnnotation {
parent.showUserView.toggle()
selectedAnnotationName = annotation.title ?? ""
}
}
// ... existing code ...
}
Upvotes: 1
Views: 121
Reputation: 3499
Currently, that tap gesture recognizer is configured to be fired whenever the user taps anywhere on the map view, not just a specific annotation. However, the method that gets called is expecting the gesture recognizer to be installed on a specific annotation view, which is not the case, so nothing happens
Rather than set up your own tap gesture recognizer, your Coordinator
should implement mapView(_:didSelect:)
, which MapKit calls when the user selected an annotation, and it will give you the view that was tapped. You can do whatever manipulation you'd like from there. If all you need is the annotation itself (not the annotation view) and your build target is at least iOS 16.0, it would probably be even more straightforward to implement the version that takes an MKAnnotation
directly
Upvotes: 1