We have already discussed the Map kit framework concepts like Map annotations and drawing path between two destinations in our earlier tutorials. In this tutorial I will be looking into zooming part of map view in such a way cover all the annotations. Before going further, I will explain some fundamentals of map kit framework.
The MapKit allows simple access to the map seen in the maps application. Using GoogleMaps as its engine the map kit allows for a developer to make their own custom map interface to fit their own application. In this tutorial I will take four annotations in a different locations(latitude and longitude) latter I will zoom the map to cover all the annotations . For this purpose I will create my own custom map view along with custom annotations and its views.
Create project in Xcode using single window application template and name it as MapZooming. Before proceeding further we need to add mapKit and coreLocation frameworks to the application bundle. I am not digging into the details of adding the frameworks into the project because it is quite common in all applications. Now open ViewController.xib file, add a map view outlet and connect it with the associated outlet in .h file. Open ViewController.h file, import MapKit framework into it and also modify it as follows.
@property (nonatomic, retain)IBOutlet MKMapView *mapView;
- (void)initiateStaticAnnotations;
- (MKCoordinateRegion)regionFromLocations;
- (void)zoomToCoverAllPoints;
-(void)zoomToFitMapAnnotations;
- (IBAction)outsideLocation:(id)sender;
- (IBAction)currentLocation:(id)sender;
@end
Now compile and run the code, you will get the following screenshot.
If you want to make the round shaped corners for the map view we need to import the QuartzCore/CALayer.h header in ViewController.m file and also add the following code in viewDidLoad method of this class to get the desired effect.
mapView.layer.masksToBounds = YES;
Now run the code to see the proper corner radius effect. In this tutorial I am not going to add any rounded corners to the map view shown earlier.To add the annotations to this map view, we need to take a new class with subclass of NSObject and name it as MapAnnotation. Open MapAnnotation.h file and change it according to the following code.
@interface MapAnnotation : NSObject
{
CLLocationCoordinate2D coordinate;
NSString *subTitleText;
NSString *titleText;
}
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (readwrite, retain) NSString *titleText;
@property (readwrite, retain) NSString *subTitleText;
-(id)initWithCoordinate:(CLLocationCoordinate2D) coordinate;
- (NSString *)subTitle;
- (NSString *)title;
-(void)setTitle:(NSString*)strTitle;
-(void)setSubTitle:(NSString*)strSubTitle;
@end
Now open MapAnnotation.m file and include the below code.
@synthesize coordinate, titleText, subTitleText;
- (NSString *)subtitle{
return subTitleText;
}
- (NSString *)title{
return titleText;
}
-(void)setTitle:(NSString*)strTitle {
self.titleText = strTitle;
}
-(void)setSubTitle:(NSString*)strSubTitle {
self.subTitleText = strSubTitle;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D) c{
coordinate=c;
return self;
}
@end
Now import the MapAnnotation class in ViewController.m file, add the initiateStaticAnnotations method in it and call this method from viewDidLoad method of this class. Implement initiateStaticAnnotations method in the following way.
{
CLLocationCoordinate2D location1;
location1.latitude = 32.805745;
location1.longitude = -96.811523;
MapAnnotation *addAnnotation1 = [[MapAnnotation alloc] initWithCoordinate:location1];
[addAnnotation1 setTitle:@"One"];
[addAnnotation1 setSubTitle:@"Subtitle"];
CLLocationCoordinate2D location2;
location2.latitude = 14.349548;
location2.longitude = -14.501953;
MapAnnotation *addAnnotation2 = [[MapAnnotation alloc] initWithCoordinate:location2];
[addAnnotation2 setTitle:@"Two"];
[addAnnotation2 setSubTitle:@"Subtitle"];
CLLocationCoordinate2D location3;
location3.latitude = 47.338823;
location3.longitude = -120.541992;
MapAnnotation *addAnnotation3 = [[MapAnnotation alloc] initWithCoordinate:location3];
[addAnnotation3 setTitle:@"Three"];
[addAnnotation3 setSubTitle:@"Subtitle"];
CLLocationCoordinate2D location4;
location4.latitude = 41.277806;
location4.longitude = -96.064453;
MapAnnotation *addAnnotation4 = [[MapAnnotation alloc] initWithCoordinate:location4];
[addAnnotation4 setTitle:@"Four"];
[addAnnotation4 setSubTitle:@"Subtitle"];
arr = [NSArray arrayWithObjects:addAnnotation1,addAnnotation2,addAnnotation3,addAnnotation4,nil];
[mapView addAnnotations:arr];
}
In this method I have taken 4 locations/annotations. To show these annotations in the respected places, we need to implement map view delegate method for annotations in the ViewController.m as follows.
{
MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MyPin"];
annView.animatesDrop=TRUE;
annView.canShowCallout = YES;
[annView setSelected:YES];
annView.pinColor = MKPinAnnotationColorRed;
annView.calloutOffset = CGPointMake(15, 15);
return annView;
}
Now build and run the code, you will see the two annotations. After tapping on one annotation you will get the following screen. Drag the map view to the left side to see the remaining two annotations and its views.
Here we have totally 4 annotations. After adding all annotations we are not able to see all the four annotations in a single view. i.e without dragging the screen to some particular side, it is not possible to view all the four annotations. To over come this, we need to zoom the map view in such a way to cover all the four annotations. Add the following method in the ViewController.m file. This method will take care of zooming level to cover all annotations.
{
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;
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1;
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
}
Call this method at the end of initiateStaticAnnotations method of ViewController.m file and you will see the following screenshot.
In the above method we have used CLLocationCoordinate2D object to make the map fit to all annotations. If you want to use only Map kit type object, the following method will be efficient.
{
// MKMapPoint annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
// MKMapRect zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0.1, 0.1);
MKMapRect zoomRect = MKMapRectNull;
for (id <MKAnnotation> annotation in mapView.annotations) {
MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
if (MKMapRectIsNull(zoomRect)) {
zoomRect = pointRect;
} else {
zoomRect = MKMapRectUnion(zoomRect, pointRect);
}
}
[mapView setVisibleMapRect:zoomRect animated:YES];
}
In this method, for each annotation we will calculate the MKMapRect object. Based on the annotation coordinates we will combined the instance map rect object with local object.