Root Draw On Map in iPhone

Introduction

In this article I will create a Single View application. We use a table, text field, label and button from outlet. We draw a path between two locations in a map. For this here we use the "MapKit Framework" that is required to implement a map view and annotation pin. It is an app that is used to dictate the path between two locations.

To understand it we use the following.

Step 1

Open XCode by double-clicking on it.

Step 2

Create a New XCode Project by clicking on it.

Step 3

Now Select Single View Application and click on Next.

Step 4

Now provide your Product Name and Company Identifier.

Step 5

Select the location where you want to save your project and click on Create.

Step 6 

First we import the framework "MapKit" that is required. 

Step 7

Now here we write the code.

MapAppDelegate.h

#import <UIKit/UIKit.h>
@class MapViewController;
@interface MapAppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) MapViewController *viewController;
@property (nonatomic, strong) UINavigationController *navigationController;
@end

MapAppDelegate.m

#import "MapAppDelegate.h"
#import "MapViewController.h"
@implementation MapAppDelegate
@synthesize window;
@synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.viewController = [[[MapViewController alloc] initWithNibName:@"MapViewController" bundle:nil] autorelease];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:_viewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
@end

MapViewController.h

#import <UIKit/UIKit.h>
#import "MapDirectionsViewController.h"
@interface MapViewController : UIViewController<UITextFieldDelegate> {
UITextField *startField;
UITextField *endField;
NSMutableArray *wayPointFields;
IBOutlet UIButton *searchbtn;
IBOutlet UITableViewController *table;
}
-(IBAction)searchPath:(id)sender;
@property(nonatomic,strong)IBOutlet UIButton *searchbtn;
@property(nonatomic,strong)IBOutlet UITableViewController *table;
@end

MapViewController.m

#import "MapViewController.h"
@interface MapViewController ()
@end
@implementation MapViewController
@synthesize searchbtn,table;
- (void)viewDidLoad {
[super viewDidLoad];
wayPointFields = [[NSMutableArray alloc] init];
self.title = @"Root Draw";
}
-(IBAction)searchPath:(id)sender
{
MapDirectionsViewController *controller = [[MapDirectionsViewController alloc] init];
controller.startPoint = startField.text;
controller.endPoint = endField.text;
NSMutableArray *wayPoints = [NSMutableArray arrayWithCapacity:[wayPointFields count]];
for (UITextField *pointField in wayPointFields) {
if ([pointField.text length] > 0) {
[wayPoints addObject:pointField.text];
}
}
controller.wayPoints = wayPoints;
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)done:(id)sender {
if ([startField canResignFirstResponder]) {
[startField resignFirstResponder];
}
if ([endField canResignFirstResponder]) {
[endField resignFirstResponder];
}
[self.navigationItem setRightBarButtonItem:nil animated:YES];
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
UIBarButtonItem *doneButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)] autorelease];
[self.navigationItem setRightBarButtonItem:doneButton animated:YES];
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
[self.navigationItem setRightBarButtonItem:nil animated:YES];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([textField resignFirstResponder] && textField == startField) {
[endField becomeFirstResponder];
}
return YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", indexPath.section, indexPath.row];
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
if (indexPath.section == 0 && indexPath.row == 0) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryNone;
UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 13.0f, 40.0f, 20.0f)];
[cell addSubview:textLabel];
[textLabel release];
textLabel.text = NSLocalizedString(@"Start:", nil);
textLabel.font = [UIFont boldSystemFontOfSize:14.0f];
// textLabel.textAlignment = UITextAlignmentRight;
textLabel.textColor = [UIColor lightGrayColor];
UITextField *inputField = [[UITextField alloc] initWithFrame:CGRectMake(66.0f, 11.0f, 236.0f, 22.0f)];
inputField.delegate = self;
[cell addSubview:inputField];
[inputField release];
[inputField setBorderStyle:UITextBorderStyleNone];
[inputField setAdjustsFontSizeToFitWidth:NO];
[inputField setClearButtonMode:UITextFieldViewModeWhileEditing];
[inputField setClearsOnBeginEditing:NO];
[inputField setPlaceholder:nil];
[inputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[inputField setAutocorrectionType:UITextAutocorrectionTypeNo];
[inputField setEnablesReturnKeyAutomatically:YES];
[inputField setKeyboardType:UIKeyboardTypeDefault];
[inputField setReturnKeyType:UIReturnKeyNext];
[inputField setEnablesReturnKeyAutomatically:YES];
[inputField setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];
[inputField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[inputField setText:[NSString stringWithUTF8String:"delhi"]];
startField = inputField;
} else if (indexPath.section == 0 && indexPath.row == 1 ) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryNone;
UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 13.0f, 40.0f, 20.0f)];
[cell addSubview:textLabel];
[textLabel release];
textLabel.text = NSLocalizedString(@"End:", nil);
textLabel.font = [UIFont boldSystemFontOfSize:14.0f];
// textLabel.textAlignment = UITextAlignmentRight;
textLabel.textColor = [UIColor lightGrayColor];
UITextField *inputField = [[UITextField alloc] initWithFrame:CGRectMake(66.0f, 11.0f, 236.0f, 22.0f)];
inputField.delegate = self;
[cell addSubview:inputField];
[inputField release];
[inputField setBorderStyle:UITextBorderStyleNone];
[inputField setAdjustsFontSizeToFitWidth:NO];
[inputField setClearButtonMode:UITextFieldViewModeWhileEditing];
[inputField setClearsOnBeginEditing:NO];
[inputField setPlaceholder:nil];
[inputField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[inputField setAutocorrectionType:UITextAutocorrectionTypeNo];
[inputField setEnablesReturnKeyAutomatically:YES];
[inputField setKeyboardType:UIKeyboardTypeDefault];
[inputField setReturnKeyType:UIReturnKeyDone];
[inputField setEnablesReturnKeyAutomatically:YES];
[inputField setContentVerticalAlignment:UIControlContentVerticalAlignmentBottom];
[inputField setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[inputField setText:[NSString stringWithUTF8String:"jaipur"]];
endField = inputField;
}
return cell;
}
@end

MapDirectionsViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "UICGDirections.h"
@class UICRouteOverlayMapView;
@interface MapDirectionsViewController : UIViewController<MKMapViewDelegate, UICGDirectionsDelegate> {
MKMapView *routeMapView;
UICRouteOverlayMapView *routeOverlayView;
UICGDirections *diretions;
NSString *startPoint;
NSString *endPoint;
NSArray *wayPoints;
UICGTravelModes travelMode;
}
@property (nonatomic, retain) NSString *startPoint;
@property (nonatomic, retain) NSString *endPoint;
@property (nonatomic, retain) NSArray *wayPoints;
@property (nonatomic) UICGTravelModes travelMode;
- (void)update;
@end

MapDirectionsViewController.m

#import "MapDirectionsViewController.h"
#import "RouteListViewController.h"
#import "UICRouteOverlayMapView.h"
#import "UICRouteAnnotation.h"

@interface MapDirectionsViewController ()
@end
@implementation MapDirectionsViewController
@synthesize startPoint;
@synthesize endPoint;
@synthesize wayPoints;
@synthesize travelMode;

- (void)dealloc {
[routeOverlayView release];
[startPoint release];
[endPoint release];
[wayPoints release];
[super dealloc];
}

- (void)loadView {
UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 372.0f)];
self.view = contentView;
[contentView release];
routeMapView = [[MKMapView alloc] initWithFrame:contentView.frame];
routeMapView.delegate = self;
routeMapView.showsUserLocation = YES;
[contentView addSubview:routeMapView];
[routeMapView release];
routeOverlayView = [[UICRouteOverlayMapView alloc] initWithMapView:routeMapView];
UIBarButtonItem *space = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
UIBarButtonItem *currentLocationButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reticle.png"] style:UIBarButtonItemStylePlain target:self action:@selector(moveToCurrentLocation:)] autorelease];
UIBarButtonItem *mapPinButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"map_pin.png"] style:UIBarButtonItemStylePlain target:self action:@selector(addPinAnnotation:)] autorelease];
UIBarButtonItem *routesButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"list.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showRouteListView:)] autorelease];
self.toolbarItems = [NSArray arrayWithObjects:currentLocationButton, space, mapPinButton, routesButton, nil];
[self.navigationController setToolbarHidden:NO animated:NO];
diretions = [UICGDirections sharedDirections];
diretions.delegate = self;
}
- (void)viewDidLoad {
[super viewDidLoad];
if (diretions.isInitialized) {
[self update];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)update {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
UICGDirectionsOptions *options = [[[UICGDirectionsOptions alloc] init] autorelease];
options.travelMode = travelMode;
if ([wayPoints count] > 0) {
NSArray *routePoints = [NSArray arrayWithObject:startPoint];
routePoints = [routePoints arrayByAddingObjectsFromArray:wayPoints];
routePoints = [routePoints arrayByAddingObject:endPoint];
[diretions loadFromWaypoints:routePoints options:options];
} else {
[diretions loadWithStartPoint:startPoint endPoint:endPoint options:options];
}
}

- (void)moveToCurrentLocation:(id)sender {
[routeMapView setCenterCoordinate:[routeMapView.userLocation coordinate] animated:YES];
}

- (void)addPinAnnotation:(id)sender {
UICRouteAnnotation *pinAnnotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[routeMapView centerCoordinate]
title:nil
annotationType:UICRouteAnnotationTypeWayPoint] autorelease];
[routeMapView addAnnotation:pinAnnotation];
}
- (void)showRouteListView:(id)sender {
RouteListViewController *controller = [[RouteListViewController alloc] initWithStyle:UITableViewStyleGrouped];
controller.routes = diretions.routes;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self presentModalViewController:navigationController animated:YES];
[controller release];
[navigationController release];
}

- (void)directionsDidFinishInitialize:(UICGDirections *)directions {
[self update];
}
- (void)directions:(UICGDirections *)directions didFailInitializeWithError:(NSError *)error {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Map Directions" message:[error localizedFailureReason] delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alertView show];
[alertView release];
}
- (void)directionsDidUpdateDirections:(UICGDirections *)directions {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
UICGPolyline *polyline = [directions polyline];
NSArray *routePoints = [polyline routePoints];
[routeOverlayView setRoutes:routePoints];
UICRouteAnnotation *startAnnotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[[routePoints objectAtIndex:0] coordinate]
title:startPoint
annotationType:UICRouteAnnotationTypeStart] autorelease];
UICRouteAnnotation *endAnnotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[[routePoints lastObject] coordinate]
title:endPoint
annotationType:UICRouteAnnotationTypeEnd] autorelease];
if ([wayPoints count] > 0) {
NSInteger numberOfRoutes = [directions numberOfRoutes];
for (NSInteger index = 0; index < numberOfRoutes; index++) {
UICGRoute *route = [directions routeAtIndex:index];
CLLocation *location = [route endLocation];
UICRouteAnnotation *annotation = [[[UICRouteAnnotation alloc] initWithCoordinate:[location coordinate]
title:[[route endGeocode] objectForKey:@"address"]
annotationType:UICRouteAnnotationTypeWayPoint] autorelease];
[routeMapView addAnnotation:annotation];
}
}
[routeMapView addAnnotations:[NSArray arrayWithObjects:startAnnotation, endAnnotation, nil]];
}
- (void)directions:(UICGDirections *)directions didFailWithMessage:(NSString *)message {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Map Directions" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alertView show];
[alertView release];
}
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
routeOverlayView.hidden = YES;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
routeOverlayView.hidden = NO;
[routeOverlayView setNeedsDisplay];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *identifier = @"RoutePinAnnotation";
if ([annotation isKindOfClass:[UICRouteAnnotation class]]) {
MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(!pinAnnotation) {
pinAnnotation = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
}
if ([(UICRouteAnnotation *)annotation annotationType] == UICRouteAnnotationTypeStart) {
pinAnnotation.pinColor = MKPinAnnotationColorGreen;
} else if ([(UICRouteAnnotation *)annotation annotationType] == UICRouteAnnotationTypeEnd) {
pinAnnotation.pinColor = MKPinAnnotationColorRed;
} else {
pinAnnotation.pinColor = MKPinAnnotationColorPurple;
}
pinAnnotation.animatesDrop = YES;
pinAnnotation.enabled = YES;
pinAnnotation.canShowCallout = YES;
return pinAnnotation;
} else {
return [routeMapView viewForAnnotation:routeMapView.userLocation];
}}
@end

RootListViewController.h

#import <UIKit/UIKit.h>
@interface RouteListViewController : UITableViewController {
NSArray *routes;
}
@property (nonatomic, retain) NSArray *routes;

@end

RootListViewController.m

#import "RouteListViewController.h"
#import "UICGRoute.h"
#import "UICGStep.h"

@interface UITextView(HTML)
- (void)setContentToHTMLString:(id)fp8;
@end
@implementation RouteListViewController
@synthesize routes;
- (void)dealloc {
[routes release];
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
target:self
action:@selector(dismiss:)] autorelease];
self.title = NSLocalizedString(@"Routes", nil);
self.tableView.rowHeight = 60.0f;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dismiss:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [routes count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
UICGRoute *route = [routes objectAtIndex:section];
return [route numerOfSteps];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
UICGRoute *route = [routes objectAtIndex:section];
return [route.summaryHtml stringByReplacingOccurrencesOfString:@"&nbsp;" withString:@" "];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20.0f, 2.0f, 280.0f, 56.0f)];
textView.editable = NO;
textView.scrollEnabled = NO;
textView.opaque = YES;
textView.backgroundColor = [UIColor whiteColor];
textView.tag = 1;
[cell addSubview:textView];
[textView release];
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
UICGRoute *route = [routes objectAtIndex:indexPath.section];
UICGStep *step = [route stepAtIndex:indexPath.row];
UITextView *textView = (UITextView *)[cell viewWithTag:1];
[textView setContentToHTMLString:step.descriptionHtml];
}
@end

Step 8

Finally we click on the run button to show the output.

Output

Output 1 in iPhone:

Output1-in-iPhone.png

Output 2 in iPhone:

Output2-in-iPhone.png

Output 3 in iPhone:

Output3-in-iPhone.png

Output 4 in iPhone:

Output4-in-iPhone.png