5

I've been working with MKMapView in iOS 7 trying to set and get programatically the zoom level in order to download and reuse map tiles when I were offline.

As I can't download the whole map into my phone, I download just several tiles in an appropriated zoom level and, afterwards I fix that zoom level and use the tiles thought MKTileOverlay and MKTileOverlayRenderer.

I tried to use Troybrant's algorithm (http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview) but it didn't worked well for me. It failed to establish the zoom level back properly.

So I created one of my own that works fine.

Some explanations about my own method:

  • At the maximum map zoom level (20), you would see every map point at 1:1 scale. The whole map would have 256*2^20 points.

  • In retina displays there is a 2.0 scale factor between map points and pixels.

  • Apple maps can vary zoom level from 3 to 19 (min & max)

  • Then there is a simple inverse rule:

    • At maximum zoom level our view will show as much points as pixels it has (with the point-pixel scale factor of 2.0 for retina displays)
    • If zoom level is decreased the amount of map points shown should increase (inverse rule)


With that information the idea is to set the MKMapView's visibleRect property:

visibleRect width points = 2.0 * mapView.bounds.size.width * 2^(20-zoom)

Using that formula I've been able to centre my maps and apply to them zoom levels properly.


As Troybrant did, I created a category with the following methods:

@interface MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                  animated:(BOOL)animated;
@end

@implementation MKMapView (ZoomLevel)

- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
                  zoomLevel:(NSUInteger)zoomLevel
                  animated:(BOOL)animated
{
    MKMapPoint centrePoint = MKMapPointForCoordinate(centreCoord);

    CGFloat rectWidth = 2.0 * self.bounds.size.width * pow(2, 20-zoomLevel);
    CGFloat rectHeight = 2.0 * self.bounds.size.height * pow(2, 20-zoomLevel);

    MKMapRect visibleRect = MKMapRectMake(centrePoint.x-rectWidth/2, centrePoint.y-rectHeight/2, rectWidth, rectHeight);

    [self setVisibleMapRect:visibleRect animated:animated];
}

@end


I hope this code can help you all.

JZarzuela
  • 502
  • 4
  • 11

0 Answers0