Showing MKAnnotation callout when clustered

Viewed 1876

I have a TableView that is used to show MapView annotation callouts when the cells are tapped.
In iOS 10 I can centre the MapView on an annotation then show it's callout using:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let location = locations[indexPath.item]
    mapView.setCenter(location.coordinate, animated: true)
    mapView.selectAnnotation(location, animated: true)
}

locations is an array of MKAnnotations. I'm using MKPinAnnotationViews on iOS 10 and MKMarkerAnnotationViews on iOS 11.

iOS 11 automatically hides and shows MKMarkerAnnotationViews as you zoom the map.

enter image description here

This has the unfortunate side effect of preventing .selectAnnotation() from working reliably because the marker could still be hidden after centering the map.

I've seen the docs and understand why:

If the specified annotation is not onscreen, and therefore does not have an associated annotation view, this method has no effect.

Is there a way to disable annotation clustering/hiding? Or some way to force the selected annotation to be visible?

1 Answers

You can set the displayPriority of an MKMarkerAnnotationView to a rawValue of 1000 and the less interesting MKMarkerAnnotationView's displayPriority to something lower. This will cause that marker annotation to take precedence over others.

In your case, you will like want to hold a reference to the annotation that you would like to select, remove that annotation from the map view and add it again. This will cause the map view to request a view for the annotation again and you can adjust the priority so that it is higher than the annotations around it. For example:

    func showAnnotation()
    {
        self.specialAnnotation = annotations.last
        self.mapView.removeAnnotation(self.specialAnnotation)
        self.mapView.addAnnotation(self.specialAnnotation)
        self.mapView.setCenter(self.specialAnnotation.coordinate, animated: true)
        self.mapView.selectAnnotation(self.specialAnnotation, animated: true)
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
    {
        let markerView = mapView.dequeueReusableAnnotationView(withIdentifier: "Marker", for: annotation) as? MKMarkerAnnotationView
        let priority = (annotation as? Annotation) == self.specialAnnotation ? 1000 : 500
        markerView?.displayPriority = MKFeatureDisplayPriority(rawValue: priority)
        // optionally change the tint color for the selected annotation
        markerView?.markerTintColor = priority == 1000 ? .blue : .red
        return markerView
    }

Where specialAnnotation is an object that conforms to MKAnnotation.

Related