Setting the zoom level for a MKMapView

I have a map which shows correctly, the only thing I want to do now is set the zoom level when it loads. Is there a way to do this?

Thanks

131006 次浏览

It's not built in, but I've seen / used this code. This allows you to use this:

[mapView setCenterCoordinate:myCoord zoomLevel:13 animated:YES];

Note: This is not my code, I did not write it, so therefore can't take credit for it

You can also zoom by using MKCoordinateRegion and setting its span latitude & longitude delta. Below is a quick reference and here is the iOS reference. It won't do anything fancy but should allow you to set zoom when it draws the map.


MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
mapView.region = region;

Edit 1:

MKCoordinateRegion region;
region.center.latitude = {desired lat};
region.center.longitude = {desired lng};
region.span.latitudeDelta = 1;
region.span.longitudeDelta = 1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:TRUE];

I found myself a solution, which is very simple and does the trick. Use MKCoordinateRegionMakeWithDistance in order to set the distance in meters vertically and horizontally to get the desired zoom. And then of course when you update your location you'll get the right coordinates, or you can specify it directly in the CLLocationCoordinate2D at startup, if that's what you need to do:

CLLocationCoordinate2D noLocation;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500);
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits:viewRegion];
[self.mapView setRegion:adjustedRegion animated:YES];
self.mapView.showsUserLocation = YES;

Swift:

let location = ...
let region = MKCoordinateRegion( center: location.coordinate, latitudinalMeters: CLLocationDistance(exactly: 5000)!, longitudinalMeters: CLLocationDistance(exactly: 5000)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)

I hope following code fragment would help you.

- (void)handleZoomOutAction:(id)sender {
MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.s       pan.latitudeDelta/0.5, mapView.region.span.longitudeDelta/0.5));
[mapView setRegion:newRegion];
}




- (void)handleZoomInAction:(id)sender {
MKCoordinateRegion newRegion=MKCoordinateRegionMake(mapView.region.center,MKCoordinateSpanMake(mapView.region.span.latitudeDelta*0.5, mapView.region.span.longitudeDelta*0.5));
[mapView setRegion:newRegion];
}

You can choose any value in stead of 0.5 to reduce or increase zoom level. I have used these methods on click of two buttons.

Based on the fact that longitude lines are spaced apart equally at any point of the map, there is a very simple implementation to set the centerCoordinate and zoomLevel:

@interface MKMapView (ZoomLevel)


@property (assign, nonatomic) NSUInteger zoomLevel;


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


@end




@implementation MKMapView (ZoomLevel)


- (void)setZoomLevel:(NSUInteger)zoomLevel {
[self setCenterCoordinate:self.centerCoordinate zoomLevel:zoomLevel animated:NO];
}


- (NSUInteger)zoomLevel {
return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1;
}


- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
[self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}


@end

I know this is a late reply, but I've just wanted to address the issue of setting the zoom level myself. goldmine's answer is great but I found it not working sufficiently well in my application.

On closer inspection goldmine states that "longitude lines are spaced apart equally at any point of the map". This is not true, it is in fact latitude lines that are spaced equally from -90 (south pole) to +90 (north pole). Longitude lines are spaced at their widest at the equator, converging to a point at the poles.

The implementation I have adopted is therefore to use the latitude calculation as follows:

@implementation MKMapView (ZoomLevel)


- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate
zoomLevel:(NSUInteger)zoom animated:(BOOL)animated
{
MKCoordinateSpan span = MKCoordinateSpanMake(180 / pow(2, zoom) *
self.frame.size.height / 256, 0);
[self setRegion:MKCoordinateRegionMake(coordinate, span) animated:animated];
}


@end

Hope it helps at this late stage.

Based on @AdilSoomro's great answer. I have come up with this:

@interface MKMapView (ZoomLevel)
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel
animated:(BOOL)animated;


-(double) getZoomLevel;
@end






@implementation MKMapView (ZoomLevel)


- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(NSUInteger)zoomLevel animated:(BOOL)animated {
MKCoordinateSpan span = MKCoordinateSpanMake(0, 360/pow(2, zoomLevel)*self.frame.size.width/256);
[self setRegion:MKCoordinateRegionMake(centerCoordinate, span) animated:animated];
}




-(double) getZoomLevel {
return log2(360 * ((self.frame.size.width/256) / self.region.span.longitudeDelta));
}


@end

Swift implementation

import Foundation
import MapKit


class MapViewWithZoom: MKMapView {


var zoomLevel: Int {
get {
return Int(log2(360 * (Double(self.frame.size.width/256) / self.region.span.longitudeDelta)) + 1);
}


set (newZoomLevel){
setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
}
}


private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool) {
let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, Double(zoomLevel)) * Double(self.frame.size.width) / 256)
setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
}
}

A simple Swift implementation, if you use outlets.

@IBOutlet weak var mapView: MKMapView! {
didSet {
let noLocation = CLLocationCoordinate2D()
let viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500)
self.mapView.setRegion(viewRegion, animated: false)
}
}

Based on @Carnal's answer.

A Swift 2.0 answer utilising NSUserDefaults to save and restore the map's zoom and position.

Function to save the map position and zoom:

func saveMapRegion() {
let mapRegion = [
"latitude" : mapView.region.center.latitude,
"longitude" : mapView.region.center.longitude,
"latitudeDelta" : mapView.region.span.latitudeDelta,
"longitudeDelta" : mapView.region.span.longitudeDelta
]
NSUserDefaults.standardUserDefaults().setObject(mapRegion, forKey: "mapRegion")
}

Run the function each time the map is moved:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool)
{
saveMapRegion();
}

Function to save the map zoom and position:

func restoreMapRegion()
{
if let mapRegion = NSUserDefaults.standardUserDefaults().objectForKey("mapRegion")
{


let longitude = mapRegion["longitude"] as! CLLocationDegrees
let latitude = mapRegion["latitude"] as! CLLocationDegrees
let center = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)


let longitudeDelta = mapRegion["latitudeDelta"] as! CLLocationDegrees
let latitudeDelta = mapRegion["longitudeDelta"] as! CLLocationDegrees
let span = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)


let savedRegion = MKCoordinateRegion(center: center, span: span)


self.mapView.setRegion(savedRegion, animated: false)
}
}

Add this to viewDidLoad:

restoreMapRegion()

For Swift 3 it's pretty fast forward:

private func setMapRegion(for location: CLLocationCoordinate2D, animated: Bool)
{
let viewRegion = MKCoordinateRegionMakeWithDistance(location, <#T##latitudinalMeters: CLLocationDistance##CLLocationDistance#>, <#T##longitudinalMeters: CLLocationDistance##CLLocationDistance#>)
MapView.setRegion(viewRegion, animated: animated)
}

Just define the lat-, long-Meters <CLLocationDistance> and the mapView will fit the zoom level to your values.

Swift:

Map.setRegion(MKCoordinateRegion(center: locValue, latitudinalMeters: 200, longitudinalMeters: 200), animated: true)

locValue is your coordinate.

Here, I put my answer and its working for swift 4.2.

MKMapView center and zoom in

Based on quentinadam's answer

Swift 5.1

// size refers to the width/height of your tile images, by default is 256.0
// Seems to get better results using round()
// frame.width is the width of the MKMapView


let zoom = round(log2(360 * Double(frame.width) / size / region.span.longitudeDelta))

MKMapView extension based on this answer (+ floating-point zoom level accuracy):

import Foundation
import MapKit


extension MKMapView {
var zoomLevel: Double {
get {
return log2(360 * (Double(self.frame.size.width / 256) / self.region.span.longitudeDelta)) + 1
}


set (newZoomLevel){
setCenterCoordinate(coordinate:self.centerCoordinate, zoomLevel: newZoomLevel, animated: false)
}
}


private func setCenterCoordinate(coordinate: CLLocationCoordinate2D, zoomLevel: Double, animated: Bool) {
let span = MKCoordinateSpan(latitudeDelta: 0, longitudeDelta: 360 / pow(2, zoomLevel) * Double(self.frame.size.width) / 256)
setRegion(MKCoordinateRegion(center: coordinate, span: span), animated: animated)
}
}