Finding the maximum zoom level of an MKMapView, and Knowing When I've Reached It

Viewed 206

I've seen a heck of a lot of stuff about setting the maximum zoom level, but not how to get it.

Here's the deal. I'm doing a "drill down" UI for clustered annotations. While the map can be zoomed, tapping on a cluster simply centers the map on the cluster, and halves the span.

When it reaches the end, and there is still a cluster, however, I want to be able to show a popover/callout, denoting the contents of the remaining cluster.

I am not able to check the zoom, to find out whether or not the new region I'm planning to set, will "take."

I know that, once it reaches max zoom, mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) will no longer be called, but that means that I need to play with contexts, and do a fairly complex dance.

Is there a simple way to examine an MKMapView, and see if it is at its maximum zoom?

1 Answers

OK, so no takers, then.

Here's how I did it. Clunky, but it works.

First, I set up a private instance property as a canary:

private var _lastClusterTapped: Bool = false

Next, I set up a simple delegate callback that clears the canary:

func mapView(_: MKMapView, regionWillChangeAnimated: Bool) {
    _lastClusterTapped = false
}

Then, in the code that handles a tap on the cluster, I did this:

func tappedOnClusterAnnotation(mapView inMapView: MKMapView, annotationView inAnnotationView: MKAnnotationView) {        
    // We attempt to zoom in by a certain amount. We do this by dividing the span.
    if let coords = inAnnotationView.annotation?.coordinate,
       var region = inMapView?.region {
        // The new region will be half the size of the original map region.
        region.span.latitudeDelta /= 2.0
        region.span.longitudeDelta /= 2.0
        region.center = coords // The new region will center on the annotation.
        _lastClusterTapped = true
        inMapView?.setRegion(region, animated: true)
        // If the callback did not happen (canary is still alive), then we assume we are maxed out, and call the handler.
        if _lastClusterTapped {
            // Do whatever we do, when a "locked" annotation is tapped.
        }
    }
}

I hate canaries and semaphores, but it does work.

This has the significant disadvantage of not working, if the region callbacks happen in an asynchronous fashion. It is predicated on the callback being made inline, so the canary has been cleared after the region set is done.

Related