I am using MapKit for my project and so far it has been very good. Here is a chunk of code I use for displaying and centering the map.
CLLocation *locSouthWest = [[CLLocation alloc] initWithLatitude:southWest.latitude longitude:southWest.longitude];
CLLocation *locNorthEast = [[CLLocation alloc] initWithLatitude:northEast.latitude longitude:northEast.longitude];
CLLocationDistance meters = [locSouthWest distanceFromLocation:locNorthEast];
MKCoordinateRegion region;
region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0;
region.center.longitude = (southWest.longitude + northEast.longitude) / 2.0;
region.span.latitudeDelta = meters / 111319.5;
region.span.longitudeDelta = 0.0;
[self.mapView setRegion:region animated:YES];
The problem is, that it works differently on iPhone 4 and iPhone 5.
Here is iPhone 4 (same results for iOS5 and iOS6):
and here is iPhone 5 (using the same coordinates):
Anybody experiencing the same?
MapKit has fixed zoom levels. Setting the map's region ensures that the region will be visible in the map, but does not set the exact zoom. This has several benefits, the primary one being you can't create a map that scales latitude and longitude disproportionately (leading to a confusing and/or misleading map). The frames of the maps are different sizes, so your selected region can display at different zoom levels on each device.
As an experiment, try setting the frame of the map view to the same size on both devices. Then, if you absolutely need the maps to display at the same scale you could do some math to compute the appropriate region based on the frame of the map.
These are the lines of code that are causing the difference:
region.center.latitude = (southWest.latitude + northEast.latitude) / 2.0;
region.center.longitude = (southWest.longitude + northEast.longitude) / 2.0;
Which are bound to create a difference since the screen sizes vary.
What you can do here to center the map is to use mapView.centerCoordinate
Related
Is it possible using MapKit to show a map in iPhone, like i´m doing, to display zoom controls on the map?
If not, what are the flags or methods i should use to increase and diminish the zoom, so i can created methods which will do this at the push of a button.
There aren't any built-in controls for it.
A couple of suggestions:
You can predefine some spans and store them in an array somewhere and then store your position in that array as well. Zooming in/out changes the position and gets the span.
Zooming in takes the current span and divides by 2, zooming out multiplies by 2.
You change the span in the region of the mapView. So you have to:
Get the region of the mapView.
Get the span of the region.
Change the span to what you want.
Set the regions span to the new span.
Set the mapView's region to the new region.
Here's some code for suggestion 2:
MKCoordinateRegion region = mapView.region;
MKCoordinateSpan span;
span.latitudeDelta = region.span.latitudeDelta*2;
span.longitudeDelta = region.span.longitudeDelta*2;
region.span = span;
[mapView setRegion:region animated:TRUE];
For swift 4, this is what I use:
func zoom(_ zoomin : Bool) {
var region = mapView.region;
var span = MKCoordinateSpan();
span.latitudeDelta = zoomin ? region.span.latitudeDelta / 2 : region.span.latitudeDelta * 2;
span.longitudeDelta = zoomin ? region.span.longitudeDelta / 2 : region.span.longitudeDelta * 2;
region.span = span;
mapView.setRegion(region, animated: true);
}
Off the top of my head I don't remember (at work on a windows box) if there is a switch to display the zoom controls. I assume you are talking about displaying the level of zoom, because by default you can pinch/spread the view for zoom.
If there isn't a switch to display the controls, then you will need to create a custom view layer and put it on top of the mapkit view. Then you will need to call the different functions to change the zoom level.
Those functions are all documented in the mapkit docs. Just do a search for MapKit in the documentation center.
Edit:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html#//apple_ref/doc/uid/TP40008205
According to the docs there isn't a switch to display the controls, but the zoom enabled property lets you turn the ability on and off.
So you can subscribe to the delegate function regionWillChange and use the mapView object to get the zoom level and then set your graphics accordingly.
I don't think you should do that, the expected way to zoom in and out is using the pinch gestures. However if you still want to go ahead and do it, you should place yourself the buttons over the MKMapView, and then with those modify the region property of the MKMapView
MKMapView returns an invalid region under iOS 5 -- latitude + latitudeDelta/2 is over 100 and shouldn't be over 90.
Has anyone seen this problem?
Steps to Reproduce:
Create an MKMapView
Log the mapView.region from within the regionDidChangeAnimated delegate method
Zoom out the map as far as possible and drag it to the right, so the view is scrolled to the top/left
Expected Results:
In iOS 4, the mapView.region is reasonable:
lat=2.202047 lon=-67.500000 latDelta=165.698164 lonDelta=225.000000
In iOS 5, however, the mapView.region is out of bounds:
lat=17.978733 lon=-67.500000 latDelta=165.698164 lonDelta=225.000000
Latitudes should be within the -90 to 90 range. However, in iOS 5, lat + latDelta/2 is 100.827815. That is not possible. While I can clamp the values at +/- 90, the offset difference is causing problems with our overlays.
Regression:
Does not happen in iOS 4.3. Happens regularly in iOS 5. Screen dumps of the map views look identical even though the center latitude is 15 degrees off.
Notes:
Project file and screen dumps can be downloaded here.
This seems to be an adequate workaround. Rather than reading the mapView.region property, call this method instead:
#implementation MKMapView(fixedRegion)
-(MKCoordinateRegion) fixedRegion_
{
// this call is broken on iOS 5, as is the region property, so don't use them
// return( [self convertRect:self.bounds toRegionFromView:self] );
CLLocationCoordinate2D topLeft = [self convertPoint:CGPointZero toCoordinateFromView:self];
CLLocationCoordinate2D bottomRight = [self convertPoint:CGPointMake(self.bounds.size.width, self.bounds.size.height) toCoordinateFromView:self];
MKCoordinateRegion region;
region.center.latitude = (topLeft.latitude + bottomRight.latitude)/2;
region.center.longitude = (topLeft.longitude + bottomRight.longitude)/2;
region.span.latitudeDelta = fabs( topLeft.latitude - bottomRight.latitude );
region.span.longitudeDelta = fabs( topLeft.longitude - bottomRight.longitude );
return region;
}
#end
Now one could argue (correctly!) that this code isn't 100% correct either because the center value of a Mercator projection in lon/lat isn't really halfway between the top and bottom, but since this matches iOS 4 functionality and keeps the values within the legal range for the map, it works for me.
By using the MKMapView+ZoomLevel category, you won’t have to bother setting the region at all.
here is very good tutorial on the same
http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/
or
http://mayurbirari.wordpress.com/2011/02/07/how-to-access-mkmapkit-in-iphone/
After you perform the zoom/pinch operation try to load the region in
-(void) mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
instead in
regionDidChangeAnimated.
hope this will help..:)
I am working with a MKMapView thats visible area (zoom level) is set with a slider.
I set the visible area with a MKCoordinateRegion and setRegion:animated:.
The problem is that I don't seem to be able to get extremely precise control over the visible area. It's as if the latitude\longitude deltas snap to the default ~21 zoom levels provided by Google.
What I really want is similar to the behavior of the Map.app when pinching to zoom. It scales the view until the threshold for a new zoom level is reached, and then it renders the new map level.
Is there a simple way to access\emulate this behavior? How does it work?
Code I'm using:
MKCoordinateRegion region;
MKCoordinateSpan span;
CLLocationCoordinate2D center = {45.475969,-73.64095};
region.center = center;
span.latitudeDelta = 0.01;
span.longitudeDelta = 0.01;
region.span = span;
[mapView setRegion:region animated:TRUE];
If I use a delta of 0.01 or 0.013, I get the exact same map.
The simple answer is that MapKit does not allow you to programatically set a zoom level other than the default 21 levels supplied by google. The region span you set will always "snap" to the closest one.
Are you using setRegion:animated: ?
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html#//apple_ref/occ/instm/MKMapView/setRegion:animated:
You can set mapview's visibleMapRect to achieve continuous zooming.
Following code shows how to zoom in 1 level (it's a subclass of a MKMapView so self is an instance of MKMapView).
MKMapRect visibleRect = self.visibleMapRect;
MKMapSize size = visibleRect.size;
CGFloat aspectRatio = size.width / size.height;
CGPoint center = CGPointMake(visibleRect.origin.x + size.width/2, visibleRect.origin.y + size.height/2);
CGFloat zoomedHeight = size.height / 2; // By divide by 2, will zoom in exact 1 level
CGFloat zoomedWidth = zoomedHeight * aspectRatio;
visibleRect = MKMapRectMake(center.x - zoomedWidth/2, center.y - zoomedHeight/2, zoomedWidth, zoomedHeight);
self.visibleMapRect = visibleRect;
friends,
i am new to iphone development and just implement google map in iphone application.
now i am facing a problem with following description
i have list of latitude and longitude values when display them on map those pins are displayed on different locations.
now i want to set zoom level so that all pins are displayed on the screen.
any help would be appreciated.
If you're using an MKMapView you can use the setRegion:animated: method to change the region displayed. I would use annotationsInMapRect: to determine which annotations are being shown. Since annotationsInMapRect: returns an NSSet you could make an NSSet of all your annotations, and zoom out the MKMapView until the NSSet returned from annotationsInMapRect: matches your NSSet of all annotations.
The values 3.0 and 2.0 are only examples you can increase or decrease the values according to your requirement(how much you have to zoom) ,map is my mkmapview object
MKCoordinateSpan span;
span.latitudeDelta = 3.0;
span.longitudeDelta = 2.0;
MKCoordinateRegion region;
region.span = span;
[map setRegion:region animated:YES];
[map regionThatFits:region];
I am zooming an MKMapView to fit the bounding region of a collection of pins, however when the pins are displayed I have noticed that the zoom could ideally do with being a little tighter. My proposed solution to this was to make the region deltas slightly smaller:
// SMALL ZOOM
region.span.latitudeDelta = (upper.latitude - lower.latitude) * 0.9;
region.span.longitudeDelta = (upper.longitude - lower.longitude) * 0.9;
However I have noticed that fine adjustments don't seem to translate to a small zoom increase, is there some form of snapping on the zoom? Really small values work, as do really big ones, but just adjusting the region size by a few percent does not seem to work with the view nearly always jumping/zooming in to far and clipping my pins.
EDIT:
Quick tests showing the results of different scaling factors on the region:
// SCALE FACTOR
// V
region.span.latitudeDelta = (upper.latitude - lower.latitude) * 0.9;
region.span.longitudeDelta = (upper.longitude - lower.longitude) * 0.9;
Here are the results:
x0.5 region too small, some annotations off screen
x0.6 Same as using 1.0
x0.7 Same as using 1.0
x0.8 Same as using 1.0
x0.9 Same as using 1.0
x1.0 Original fit
x1.1 region too big, annotations too small on screen
My point is that very small adjustments (e.g. 0.6 to 0.9) don't seem to make any difference.
Smaller adjustments will never make the mapview zoom level change. When you pass a region, the mapview decides on what zoom level to use for the best fit. It will never use an "in-between" level. The reason is that the "in-between" zoom levels look fuzzy. You give it the region you want to show and it makes a zoom level that includes that whole region. Giving your desired region to regionThatFits: should return the level that it uses.
If you're zooming the map with a pinch, you can get to a level between two zoom levels, but if you double-tap (to zoom in) or do a 2-finger tap (to zoom out) you will only see the "standard" zoom levels.
I'm talking about zoom levels here, but really they don't exist in iOS in the same way they exist in Google Maps. Only regions exist as far as setting the map to a certain level.
With your problem of getting the best fit for pins, I found that something changed in iOS 4, and the code I'd used to fit pins suddenly gave too much space. I divided the deltas by 3 and it worked again. You might want to wrap this in a conditional to target only iOS 4.
region.span.longitudeDelta = (maxCoord.longitude - minCoord.longitude) / 3.0;
region.span.latitudeDelta = (maxCoord.latitude - minCoord.latitude) / 3.0;
Looking at your code, you use * 0.9 to get the exact same thing.
One of the strange things I found was that the value returned by regionThatFits: wasn't always the region that the mapview ended up setting. It might be a bug, but it's been there since iOS 4.0. You can test this yourself by logging the MKCoordinateRegion from regionThatFits: and comparing it to the mapview's region after zooming. I seem to remember it coming up on the Apple Developer Forums.
I have found this method to be extremely useful. All you need to do is call it and pass your MKMapView as the argument, and it will determine the best zoom level to fit all of your annotations. The "tightness" can be adjusted by modifying the constant multiplier on the commented lines (currently 1.1).
What's the best way to zoom out and fit all annotations in MapKit
- (void)zoomToFitMapAnnotations:(MKMapView *)mapView
{
if ([mapView.annotations count] == 0)
return;
CLLocationCoordinate2D topLeftCoord;
topLeftCoord.latitude = -90;
topLeftCoord.longitude = 180;
CLLocationCoordinate2D bottomRightCoord;
bottomRightCoord.latitude = 90;
bottomRightCoord.longitude = -180;
for (MapAnnotation *annotation in mapView.annotations)
{
topLeftCoord.longitude = fmin(topLeftCoord.longitude, annotation.coordinate.longitude);
topLeftCoord.latitude = fmax(topLeftCoord.latitude, annotation.coordinate.latitude);
bottomRightCoord.longitude = fmax(bottomRightCoord.longitude, annotation.coordinate.longitude);
bottomRightCoord.latitude = fmin(bottomRightCoord.latitude, annotation.coordinate.latitude);
}
MKCoordinateRegion region;
region.center.latitude = topLeftCoord.latitude - (topLeftCoord.latitude - bottomRightCoord.latitude) * 0.5;
region.center.longitude = topLeftCoord.longitude + (bottomRightCoord.longitude - topLeftCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
}