I got MKMapView and a number of annotations on it. I use next code for displaying all annotations:
NSArray *coordinates = [self.mapView valueForKeyPath:#"annotations.coordinate"];
CLLocationCoordinate2D maxCoord = {-90.0f, -180.0f};
CLLocationCoordinate2D minCoord = {90.0f, 180.0f};
for(NSValue *value in coordinates) {
CLLocationCoordinate2D coord = {0.0f, 0.0f};
[value getValue:&coord];
if(coord.longitude > maxCoord.longitude) {
maxCoord.longitude = coord.longitude;
}
if(coord.latitude > maxCoord.latitude) {
maxCoord.latitude = coord.latitude;
}
if(coord.longitude < minCoord.longitude) {
minCoord.longitude = coord.longitude;
}
if(coord.latitude < minCoord.latitude) {
minCoord.latitude = coord.latitude;
}
}
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center.longitude = (minCoord.longitude + maxCoord.longitude) / 2.0;
region.center.latitude = (minCoord.latitude + maxCoord.latitude) / 2.0;
region.span.longitudeDelta = (maxCoord.longitude - minCoord.longitude) * 1.5;
region.span.latitudeDelta = (maxCoord.latitude - minCoord.latitude) * 1.5;
[self.mapView setRegion:region animated:YES];
This code centers all annotations - perfect. But what if I want to fit annotations, lets say, on right half part of map. Is there any way to do that?
Here how it's now:
Here what I want to achieve:
If your target area is always to the left or right (i.e. still allowing full height) then it is very easy, you just need to work out the maths for your region's boundaries.
Let's assume you want the pins to be in the right-hand quarter of the page. This would mean you need to tell the map to view a region 4x (targetspan/currentspan) bigger than the pin region and with the middle of that region being shifted left by 1.5x ((targetspan-currentspan)/2)the width of the region. (I'm going to sat latitude is from 0 to 1 but really you just use what ever you have calculated already)
Imagine the view being divided into four vertical strips, there would be 5 lines. The left edge of the screen is 0, the next line is 1, the middle is 2, the next is 3 and the last is 4.
You want your pins to be between lines 3 and 4, meaning the longitude span you calculated above is 1 unit wide and the center.longitude is at 3.5.
You have a region that is ((3.5,0.5), (1,1)) and you need to tell your map to zoom to the region ((2,0.5),(4,1)). So, get the longitudeDelta, multiply it by 1.5 and subtract that from the center.longitude, that is your new target center.longitude. Then multiply the longitudeDelta by 4 and that is your new longitudeDelta.
You can do something similar with latitude on a small scale, but on a large scale the calculations ned to take into account the map projection which means the pixels near the equator represent more land than those near the poles.
Related
I have list of markers on my Googlemap,fixed all the markers.Now I need to get Limited Region only possible to scroll inside the limited Region.How its possible.anyone Please help me to fix it.
Here is My Center Location
let center = CLLocationCoordinate2DMake(11.250220, 75.781573)
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: center.latitude, longitude: center.longitude, zoom: 18.0)
Start by defining two locations which specify the bounds of the region you want to display. These could be opposite corners of the bounding box, or just two locations, for example:
CLLocationCoordinate2D location1 =
CLLocationCoordinate2DMake(-33.8683, 151.2086); // Sydney
CLLocationCoordinate2D location2 =
CLLocationCoordinate2DMake(-31.9554, 115.8585); // Perth
If you have more than two points that you want to include, you could calculate the bounds of them yourself. This can also be done using GMSCoordinateBounds, for example:
GMSCoordinateBounds* bounds =
[[GMSCoordinateBounds alloc]
initWithCoordinate: CLLocationCoordinate2DMake(-33.8683, 151.2086) // Sydney
andCoordinate: CLLocationCoordinate2DMake(-31.9554, 115.8585)]; // Perth
bounds = [bounds including:
CLLocationCoordinate2DMake(-12.4667, 130.8333)]; // Darwin
CLLocationCoordinate2D location1 = bounds.southWest;
CLLocationCoordinate2D location2 = bounds.northEast;
Next, you need to get the size of the map view in points. You could use this:
float mapViewWidth = _mapView.frame.size.width;
float mapViewHeight = _mapView.frame.size.height;
Now you have the info necessary to calculate the camera position:
MKMapPoint point1 = MKMapPointForCoordinate(location1);
MKMapPoint point2 = MKMapPointForCoordinate(location2);
MKMapPoint centrePoint = MKMapPointMake(
(point1.x + point2.x) / 2,
(point1.y + point2.y) / 2);
CLLocationCoordinate2D centreLocation = MKCoordinateForMapPoint(centrePoint);
double mapScaleWidth = mapViewWidth / fabs(point2.x - point1.x);
double mapScaleHeight = mapViewHeight / fabs(point2.y - point1.y);
double mapScale = MIN(mapScaleWidth, mapScaleHeight);
double zoomLevel = 20 + log2(mapScale);
GMSCameraPosition *camera = [GMSCameraPosition
cameraWithLatitude: centreLocation.latitude
longitude: centreLocation.longitude
zoom: zoomLevel];
You can then initialize the map view with this camera, or set the map view to this camera.
For this code to compile, you will need to add the MapKit framework to your project, and then also import it:
#import <MapKit/MapKit.h>
Note that this code doesn't handle wrap-around if your coordinates span across the date line. For example if you tried using this code with Tokyo and Hawaii, instead of displaying an area of the Pacific, it will try to display almost the entire world. In portrait mode it's not possible to zoom out far enough to see Hawaii on the left and Tokyo on the right, and so the map ends up centred on Africa with neither location visible. You could modify the above code to handle the wrap-around at the date line if you wanted to.
My map view contains one circle which covers many pinpoints with one center point.Whenever the user clicks a button the map should be zoomed in such a level the circle is visible.The map should not be zoomed more or less it should show exact circle.When user logs out then circle will have new radius in next login.How to calculate the appropriate zoom level.
My code:
-(void)showCircle{
//calculate new radius
long radius=[self calculateRadius];
MKCircle *circle= [[MKCircle alloc]init];
circle = [MKCircle circleWithCenterCoordinate:CLLocationCoordinate2DMake([groupLat floatValue], [groupLon floatValue]) radius:radius];
[myMapView addOverlay:circle];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake([groupLat floatValue], [groupLon floatValue]), 800, 800);
MKCoordinateSpan span;
//calculate zoom level
double radius=[circle radius]);
double rad = radius + radius / 2;
double scale = rad / 500;
zoomLevel=(16 - log(scale) / log(2));
region.span.latitudeDelta =zoomLevel;
region.span.longitudeDelta =zoomLevel;
[myMapView setRegion:region animated:YES];
}
Thank you in advance!
You can try : mapRectThatFits(:) or mapRectThatFits(:edgePadding:)
Something like this, maybe, to zoom the map according to your circle :
myMapView.visibleMapRect = [myMapView mapRectThatFits:circle.boundingMapRect];
Hope this helps you :)
I'm trying to zoom to fit annotations on a map while locking the center and providing some insets.
- (void)fitAnnotations:(NSArray *)annotations edgeInsets:(UIEdgeInsets)insets
{
CLLocationCoordinate2D originalCenter = self.centerCoordinate;
MKMapRect mapRect = MKMapRectNull;
for (id<MKAnnotation> annotation in annotations) {
MKMapPoint p = MKMapPointForCoordinate([annotation coordinate]);
mapRect = MKMapRectUnion(mapRect, MKMapRectMake(p.x, p.y, 0, 0));
}
mapRect = [self mapRectThatFits:mapRect edgePadding:insets];
MKCoordinateRegion mapRegion = MKCoordinateRegionForMapRect(mapRect);
// we now try to go back to the original center, while increasing the span by neccessary amount
MKCoordinateSpan centeringDelta = MKCoordinateSpanMake(fabs(mapRegion.center.latitude - originalCenter.latitude), fabs(mapRegion.center.longitude - originalCenter.longitude));
mapRegion.center = originalCenter;
mapRegion.span.latitudeDelta += centeringDelta.latitudeDelta * 2.0;
mapRegion.span.longitudeDelta += centeringDelta.longitudeDelta * 2.0;
mapRegion = [self regionThatFits:mapRegion];
[self setRegion:mapRegion animated:YES];
}
The first part of the code here works as expected: it zooms to fit while respecting the insets. However, it shifts the center.
I try to re-adjust the center after that, but it fails. I'm not sure if my math on the re-centering is correct.
The first part of your code that calculates the bounding map rect that fits the annotations is OK.
Only the adjustment of that "minimal" map rect so that the "locked" center is actually in the center needs to be corrected.
The main problem, I believe, is that the code in the question is adjusting the span to both re-center the region and account for the insets after calling mapRectThatFits: (which will itself already give a slightly modified version of the rect you actually requested).
Instead, your code should only calculate the actual, minimal rect it wants and then finally call setVisibleMapRect:edgePadding:animated: and let the map view figure out both the "rect that fits" and the insets.
Please try the following:
- (void)fitAnnotations:(NSArray *)annotations edgeInsets:(UIEdgeInsets)insets
{
MKMapPoint centerMapPoint = MKMapPointForCoordinate(originalCenter);
//--- First create minimal bounding map rect to tightly fit annotations...
MKMapRect minimalMapRect = MKMapRectNull;
for (id<MKAnnotation> annotation in annotations) {
MKMapPoint annMapPoint = MKMapPointForCoordinate(annotation.coordinate);
minimalMapRect = MKMapRectUnion(minimalMapRect, MKMapRectMake(annMapPoint.x, annMapPoint.y, 0, 0));
}
//--- Now create adjusted map rect so center coordinate is in the center...
//distance of desired center from minimal left edge...
double centerXOffset = centerMapPoint.x - minimalMapRect.origin.x;
//raw amount width needs to be adjusted to get center in center...
//negative/positive indicates whether center is in left/right half
double widthOffset = 2.0 * centerXOffset - minimalMapRect.size.width;
//add absolute value of raw width offset to minimal width...
double adjustedWidth = minimalMapRect.size.width + fabs(widthOffset);
//distance of desired center from minimal top edge...
double centerYOffset = centerMapPoint.y - minimalMapRect.origin.y;
//raw amount height needs to be adjusted to get center in center...
//negative/positive indicates whether center is in top/bottom half
double heightOffset = 2.0 * centerYOffset - minimalMapRect.size.height;
//add absolute value of raw height offset to minimal height...
double adjustedHeight = minimalMapRect.size.height + fabs(heightOffset);
//adjust origin if necessary (if center is in top/left half)...
MKMapPoint adjustedOrigin = minimalMapRect.origin;
if ((centerXOffset / minimalMapRect.size.width) < 0.5)
{
adjustedOrigin.x = adjustedOrigin.x + widthOffset;
}
if ((centerYOffset / minimalMapRect.size.height) < 0.5)
{
adjustedOrigin.y = adjustedOrigin.y + heightOffset;
}
//create adjusted MKMapRect...
MKMapRect adjustedMapRect = MKMapRectMake(adjustedOrigin.x, adjustedOrigin.y, adjustedWidth, adjustedHeight);
//--- Apply the adjusted map rect with insets to map view...
[mapView setVisibleMapRect:adjustedMapRect edgePadding:insets animated:YES];
}
Try something like this, where you use your calculated mapRect to create the new region with your originalCenter via the MKCoordinateRegionMake method
MKCoordinateRegion mapRegion = MKCoordinateRegionForMapRect(mapRect);
mapRegion = MKCoordinateRegionMake(originalCenter, mapRegion.span);
mapView.region = mapRegion;
Try this.
MKMapPoint center = MKMapPointForCoordinate(self.mapView.centerCoordinate);
double maxX = 0;
double maxY = 0;
for (MKPointAnnotation *a in self.mapView.annotations)
{
MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
double deltaX = fabs(center.x - p.x);
double deltaY = fabs(center.y - p.y);
maxX = MAX(maxX, deltaX);
maxY = MAX(maxY, deltaY);
}
MKMapRect rect = MKMapRectMake(center.x - maxX, center.y - maxY, maxX * 2, maxY * 2);
rect = [self.mapView mapRectThatFits:rect edgePadding:UIEdgeInsetsMake(20, 20, 20, 20)];
[self.mapView setVisibleMapRect:rect animated:1];
#moby I am thinking of a different approach. How about taking the maps centre location as you already did. Now calculate distance to each annotation from this centre coordinate till you find the longest annotation (say 'requiredDistance' ).
Get a new map rect with all your annotations plotted with same centre using below code:
MKCircle *circleLine = [MKCircle circleWithCenterCoordinate:self.centerCoordinate radius:requiredDistance];
[self.mapView setVisibleMapRect:circleLine.boundingMapRect];
Coming to your insets what ever insets you wanted to apply should be applied to your 'requiredDistace' variable in such a way that your 'requiredDistance' variable has a value always greater than or equal to the distance between your centre coordinate and your longest annotation to make sure all the annotations are always visible.
I have a question regarding setting the region on my MKMapView.
I need to set the mapview to display a specific region when my view first loads.
The north east and south west latitude and longitude of this region is:
North East Coordinate Lat:59.623724 Long:2.911587
South West Coordinate Lat:49.004833 Long:-11.361825
Further to this, I would like to 'lock' the mapview to this region. Ideally the lock will be transparent, i.e: the coordinates above represent the maximum extent of the MKMapView. However if it is simply a case of checking the northeast and southwest coordinates within
- (void)mapView:(MKMapView *)aMapView regionDidChangeAnimated:(BOOL)animated
and resetting the view if they exceed my maximum range, that would be acceptable to me also.
Many thanks for any pointers on this matter.
EDIT:
Regarding the first part of my question, I have figured out I can set the initial region on the MKMapView using the following code:
CLLocationCoordinate2D neCoord;
neCoord.latitude = 59.787643;
neCoord.longitude = 3.025857;
CLLocationCoordinate2D swCoord;
swCoord.latitude = 49.394171;
swCoord.longitude = -11.036642;
MKCoordinateRegion region;
region.center.latitude = neCoord.latitude - (neCoord.latitude - swCoord.latitude) * 0.5;
region.center.longitude = neCoord.longitude + (swCoord.longitude - neCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(neCoord.latitude - swCoord.latitude); // Add a little extra space on the sides
region.span.longitudeDelta = fabs(swCoord.longitude - neCoord.longitude); // Add a little extra space on the sides
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
First, you'll need to make sure you set the region on the map view after the view has been displayed. If you set it before the map has loaded, it probably won't center on that region. Once you've done that, just set self.mapView.zoomEnabled = NO; and self.mapView.scrollEnabled = NO; and it will prevent the user from moving the map around.
If you want to lock the maximum bounds the user can view but still allow scrolling and zooming, you will have to use -mapView:regionDidChangeAnimated: and 'bump' the user back inside your bounds if they leave it. Note that the user experience for this will probably suck - they'll pan around, let go, and then the map will suddenly move back to the region you defined. You could try using -mapView:regionWillChangeAnimated: and modify the map region if they left your boundaries, that could be a little less jarring.
I'm displaying an MKMapView inside a Path-style parallax table view header. To create the effect, the mapView bounds is larger than the area visible to the user. I need to set the map view region such that all the map's annotations are contained within the visible rect of MKMapView. What's the best way to do this?
Edit for clarity: Here's a use-case. The mapView size is 320 x 380. The visible area, however, is defined by the rect (0.0, 20.0, 320.0, 100.0). I need to set the region such that all the annotations appear in this rect within the mapView.
Setting the map region so that all annotations are contained in a certain part of an MKMapView can be done in three steps. Input are the mapView and the annotationsFrame.
Calculate an MKMapRect mapRect that contains all annotations.
Calculate the padding insets from mapView.bounds and annotationsFrame.
Call -setVisibleMapRect:edgePadding:animated: on the map view.
Below is a screen shot of a test. The red overlay shows the annotationsFrame.
Here is the code. Beware: It's all in one method to simplify adding it to your code, and it is not tested for edge cases like passing in n annotations with the same coordinate, or having the annotations so far apart that the map would have to get zoomed out too much, or having coordinates that span the edge of the map at +/-180 degrees longitude.
- (void)zoomAnnotationsOnMapView:(MKMapView *)mapView toFrame:(CGRect)annotationsFrame animated:(BOOL)animated
{
if (_mapView.annotations.count < 2) return;
// Step 1: make an MKMapRect that contains all the annotations
NSArray *annotations = _mapView.annotations;
id <MKAnnotation> firstAnnotation = [annotations objectAtIndex:0];
MKMapPoint minPoint = MKMapPointForCoordinate(firstAnnotation.coordinate);
MKMapPoint maxPoint = minPoint;
for (id <MKAnnotation> annotation in annotations) {
MKMapPoint point = MKMapPointForCoordinate(annotation.coordinate);
if (point.x < minPoint.x) minPoint.x = point.x;
if (point.y < minPoint.y) minPoint.y = point.y;
if (point.x > maxPoint.x) maxPoint.x = point.x;
if (point.y > maxPoint.y) maxPoint.y = point.y;
}
MKMapRect mapRect = MKMapRectMake(minPoint.x, minPoint.y, maxPoint.x - minPoint.x, maxPoint.y - minPoint.y);
// Step 2: Calculate the edge padding
UIEdgeInsets edgePadding = UIEdgeInsetsMake(
CGRectGetMinY(annotationsFrame),
CGRectGetMinX(annotationsFrame),
CGRectGetMaxY(mapBounds) - CGRectGetMaxY(annotationsFrame),
CGRectGetMaxX(mapBounds) - CGRectGetMaxX(annotationsFrame)
);
// Step 3: Set the map rect
[mapView setVisibleMapRect:mapRect edgePadding:edgePadding animated:animated];
}
If you go for a perfect placement (and who doesn't), here are three things to consider:
The code assures that all the coordinates are in the annotationsFrame, but the annotations themselves may be outside. To prevent that, simply use more padding. For example, if your annotations are 20x20 and centered on the coordinate, use 10 more padding on all sides.
Below iOS 7, the map was not zooming to the perfect zoom scale, but to the next tile size (power of two). So there will be more space around the annotations than needed, just as shown on the screenshot.
On iOS 7, the map view will not only zoom perfectly, but automatically care about the status bar. To make the calculation correct, you need to subtract the status bar height from the top padding on iOS 7.
Starting from iOS 7.0, this can be easily achieved with showAnnotations.
Swift:
mapView.showAnnotations(mapView.annotations, animated: true)
Objective-C:
[mapView showAnnotations:mapView.annotations animated:YES];
The above statement will adjust the map view's visible rect in order to display all annotations.
You first need to add the annotations:
(of course this is after you already have a list of annotations)
Swift4:
self.mapView.addAnnotations(annotations)
let currentView = mapView.visibleMapRect
mapView.annotations(in: currentView)
You can use the currentView constant or directly place the MKMapRect as such: Below: (.visibleMapRect returns:
"The area currently displayed by the map view."
mapView.annotations(in: mapView.visibleMapRect)
I found an easier way without calculating is let the map view calculate it, then we adjust the edges.
//1: Show all annotation on the map view, but without animation
self.mapView.showAnnotations(self.mapView.annotations, animated: false)
//2: Get the current visible map rect
let currentMapRect = self.mapView.visibleMapRect
//3: Create the edges inset that you want the map view to show all annotation within
let padding = UIEdgeInsets(top: 100, left: 100, bottom: 100, right: 100)
//4: Set current map rect but with new padding, also set animation to true to see effect
self.mapView.setVisibleMapRect(currentMapRect, edgePadding: padding, animated: true)
If you're prepared to approximate the calculations you can do it using some clever scaling.
Your target area is 80 tall out of a mapView that is 380. Therefore you want a region that is 4.75x taller than the region calculated to fit your annotations. (0.25 extra above and 3.5 extra below).
First you need to get a region (or maprect, what ever you prefer working in) and make it the same proportions as your target viewable area. This is because a really wide and short region would not be touching the top and bottom of the viewable area and therefore multiplying its height would not make something that touched the top and bottom of your map view. So if viewable_height/viewable_width > annotations_height/annotations_width you should set the annotations_height to annotations_width * (viewable_height/viewable_width).
With that you then add 25% on to the north of the annotations box and 350% on to the south. You can do this by moving the center 212.5% (of the current height) south and increasing the vertical span by 475%.
Now, all of this is an approximation given that the world is sphere and we're not looking at a planar projection (i.e. 1 degree of latitude near the equator is drawn smaller than 1 degree near the poles). But if you wally want to be accurate you could look into scaling the numbers according to latitude and such. If you're only dealing with annotations on a city-sized scale you'll probably be ok.
Hope that helps.
if you want to find the annotations that are in a given rect:
- (NSArray*)allAnnotationsInMapRect:(MKMapRect)mapRect {
NSMutableArray *annotationsInRect = [NSMutableArray array];
for(id<MKAnnotation *ann in self.allAnnotations) {
MKMapPoint pt = MKMapPointForCoordinate(ann.coordinate);
if(MKMapRectContainsPoint(mapRect, pt)) {
[annotationsInRect addObject:ann];
}
}
return annotationsInRect;
}
and to assure the annotation VIEWS are in the rect, get the region for the annotations,
then walk through them and get each view's bounds see if the bounds fit inside the visibleRect of the map and if not modify the region!
~~ like this:
- (void)assureAnnotationViewsAreVisible:(NSArray*)annotations originalRegion:(MKCoordinateRegion)originalRegion {
CGFloat smallestX = MAXFLOAT;
CGFloat smallestY = MAXFLOAT;
CGFloat biggestX = -100;
CGFloat biggestY = -100;
//NSLog(#"---: %d", annotations.count);
for(id<MKAnnotation> *annotation in annotations) {
UIView *annotationView = [self.mapView viewForAnnotation:v];
CGRect annotationViewFrame = annotationView.bounds;
annotationViewFrame.origin = [self.mapView convertCoordinate:annotationView.coordinate toPointToView:self.mapView];
annotationViewFrame.origin = CGPointMake(annotationViewFrame.origin.x-annotationViewFrame.size.width/2,
annotationViewFrame.origin.y-annotationViewFrame.size.height);
smallestX = MIN(annotationViewFrame.origin.x, smallestX);
smallestY = MIN(annotationViewFrame.origin.y, smallestY);
biggestX = MAX(annotationViewFrame.origin.x+annotationViewFrame.size.width, biggestX);
biggestY = MAX(annotationViewFrame.origin.y+annotationViewFrame.size.height, biggestY);
}
//NSLog(#"---");
CGRect bounds = self.mapView.bounds;
if(smallestX < bounds.origin.x || smallestY < bounds.origin.y || biggestX > bounds.origin.x+bounds.size.width || biggestY > bounds.origin.y+bounds.size.height) {
CGRect neededRect = bounds;
neededRect.origin = CGPointMake(MIN(bounds.origin.x, smallestX), MIN(bounds.origin.y, smallestY));
neededRect.size = CGSizeMake(MAX(bounds.size.width, biggestX), MAX(bounds.size.height, biggestY));
MKCoordinateRegion neededRegion = [self.mapView convertRect:neededRect toRegionFromView:self.mapView];
_ignoreRegionChange = YES;
[self.mapView setRegion:originalRegion animated:NO];
_ignoreRegionChange = NO;
[self.mapView setRegion:neededRegion animated:YES];
}
else {
MKCoordinateRegion currentRegion = self.mapView.region;
_ignoreRegionChange = YES;
[self.mapView setRegion:originalRegion animated:NO];
_ignoreRegionChange = NO;
[self.mapView setRegion:currentRegion animated:YES];
}
}
Try to get from all your annotation edges value (max and min) for lan and lon.
Define this value on the beginning:
static float maxLat = FLT_MIN;
static float maxLon = FLT_MIN;
static float minLat = FLT_MAX;
static float minLon = FLT_MAX;
and then use this function to calculate span and region:
- (void) zoomAndFit {
for(int i = 0; i < [self.points count]; i++) {
PRPlaceModel *place = [self.points objectAtIndex:i];
CLLocationCoordinate2D location;
location.latitude = [place.lat floatValue];
location.longitude = [place.lon floatValue];
minLat = MIN(minLat, location.latitude);
minLon = MIN(minLon, location.longitude);
maxLat = MAX(maxLat, location.latitude);
maxLon = MAX(maxLon, location.longitude);
}
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 1.2*(maxLat - minLat);
span.longitudeDelta = 1.2*(maxLon - minLon);
CLLocationCoordinate2D location;
location.latitude = (minLat + maxLat)/2;
location.longitude = (minLon + maxLon)/2;
region.span=span;
region.center=location;
[self.mapView setRegion:region animated:TRUE];
[self.mapView regionThatFits:region];
}
And use it in viewDidLoad method:
-(void)viewDidLoad
{
[super viewDidLoad];
[self zoomAndFit];
}