I am doing clustering of Annotations.
The below code works fine and clusters the points correctly in iOS 11 & iOS 12.
This fails to cluster the points decluster the points in iOS 13.
I am not using any beta versions.
The TTMapView class is wrapper for MKMapView.
class TTMapView: UIView {
var mapView = MKMapView()
private var mapObjects: Dictionary<TTShape, MKShape?> = [:]
private var _isClusteringEnabled = true
func addMarker(_ marker: TTPoint) -> TTPoint {
removeMarker(marker)
let coordinate = marker.coordinate
let pointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = convertTTCoordinateToCLLocationCoordinate2D(coordinate)
pointAnnotation.title = marker.title
pointAnnotation.subtitle = marker.subtitle
mapObjects.updateValue(pointAnnotation, forKey: marker)
mapView.addAnnotation(pointAnnotation)
return marker
}
}
extension TTMapView: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}
if _isClusteringEnabled {
let point = mapObjects.filter ({ $0.value === annotation }).first?.key as? TTPoint
print("point ", point)
return TTClusterAnnotationView(annotation: annotation, reuseIdentifier: TTClusterAnnotationView.ReuseID, image: point?.image, color: point?.tintColor)
} else {
let reuseId = "simplePin"
var pinAnnotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId)
if pinAnnotationView == nil {
pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinAnnotationView?.isDraggable = true
pinAnnotationView?.canShowCallout = true
}
return pinAnnotationView
}
}
}
class TTClusterAnnotationView: MKMarkerAnnotationView {
/// Use this Id for setting annotation
static let ReuseID = "clusterAnnotation"
init(annotation: MKAnnotation?, reuseIdentifier: String?, image: UIImage?, color: UIColor? = nil) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
// Enable clustering by just setting the clusteringIdentifier
clusteringIdentifier = "clusteringIdentifier"
glyphImage = image
glyphTintColor = color
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForDisplay() {
super.prepareForDisplay()
displayPriority = .required
}
}
Make the cluster annotation view (this is the annotation view for the cluster, not to be confused with your existing annotation view that has a
clusteringIdentifier, which I’ve renamed toCustomAnnotationViewto avoid confusion) have adisplayPriorityof.required:Then register that class:
And then use it:
A few unrelated observations:
I’d suggest just adding your image and color properties to a custom annotation type rather than having
viewForfilter throughmapObjects. So:Then, if you use that rather than
MKPointAnnotation, your custom annotation view can pull the color and image info right out of the annotation.Note, above I’m resetting the cluster identifier, image, glyph, etc. in the
didSetofannotation. This enables the reuse of annotation views. (See next point.)The reuse logic for your pin annotation view is not correct. And you’re not doing reuse at all if clustering is turned on. If targeting iOS 11 and later, I’d use
dequeueReusableAnnotationView(withIdentifier:for:)which takes care of all of this for you. So, I can register this reuse id:And I’d repeat that process for the “simple pin” annotation view that you show if you turn off clustering.
And
And then your
viewForis simplified: