Archive for the 'CloudMade' Category

25 DecRouteMe is alternative map control to Google Maps from iPhone SDK

A little bit tired cause limitations of built-in Google Maps control. It’s good chance to write some samples of using alternatives.

Theory

There are two alternative map controls I was working with:
  1. Route me
    1. BSD licensed open source. It’s up to you if it’s an advantage
    2. Support lots of sources: OpenStreetMap, Microsoft Virtual Earth, Cloud Made and even old school Yahoo Maps and some other less popular
    3. Formed discussing community – Google Group
  2. Cloud Made
    1. Piece of larger project, so officially has support team and potentially better integration with Cloud Made maps
    2. I use it at very early stage, so not sure of current quality
    3. Has tons of cool themes for maps
It’s enough of facts and theory, time for practice. As a first task let’s embed maps and give user to select the maps source. I prefer Route Me because it can show Cloud Made maps also.

Practice preparations

  1. Open xCode and create new project. I chose View-Based Application and named “RouteMeSourceSelection”.
  2. Download actual Route Me sources
  3. Setup Route Me control very accurately step by step with the Embedding Guide
Now you must have buildable project to continue. If you have some problems feel free to download the sample sources for comparing.

Add Route Me Control (code)

Open UIViewController header file (mine is “RouteMeSourceSelectionViewController.h”) and:

  1. #import “RMMapView.h”
  2. add protocol “RMMapViewDelegate”
  3. create IBOutlet RMMapView *mapView;
Open UIViewController source file and override “- (void)viewDidLoad” method:
- (void)viewDidLoad {    [super viewDidLoad][RMMapView class]; // this important, maps won't display without it [mapView setDelegate:self];}

Add Route Me Control (design)
  1. Open your .xib file in Interface Builder (IB)
  2. Add subview to existing one and set its class to RMMapView
  3. Set IBOutlet of an UIViewController to the just added RMMapView

Now run the project and you will see the maps with default Open Street View source.

All that were really easy. Now give a user possibility to select map source from UIPickerView.

Map source UIPickerView (code)

Open the controller header file and add protocols UIPickerViewDelegate and UIPickerViewDataSource, then add and several IBOutlets:

#import #import "RMMapView.h" @interface RouteMeSourceSelectionViewController : UIViewController<rmmapviewdelegate, uipickerviewdatasource="" uipickerviewdelegate,="">{ IBOutlet RMMapView *mapView; IBOutlet UIPickerView *mapSourcePicker; IBOutlet UIBarButtonItem *mapSettingsBarButton;} - (IBAction) showMapsSettings; @end
Now we should implement necessary methods for UIPickerView to let it show a list of available map sources to select:
static NSArray *titles = nil- (NSString *)pickerView:(UIPickerView *)pickerView     titleForRow:(NSInteger)row    forComponent:(NSInteger)component{ return [titles objectAtIndex:row];} - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ if (!titles) {  titles = [[NSArray alloc] initWithObjects:      @"Open Street Maps",       @"Yahoo Map",      @"Virtual Earth Aerial",       @"Virtual Earth Hybrid",       @"Virtual Earth Road",       @"Cloud Made Map",       nil]; }  return [titles count];} - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ return 1;}

Make showMapsSettings method to show/hude the UIPickerView and set some UI trifles:

- (IBAction) showMapsSettings{ BOOL toShow = [mapSourcePicker isHidden]if (toShow) {  [mapSettingsBarButton setStyle:UIBarButtonItemStyleDone]; } else // hidding {  [mapSettingsBarButton setStyle:UIBarButtonItemStyleBordered];  [self setMapSourceWithNumber:[mapSourcePicker selectedRowInComponent:0]]; }  [mapSourcePicker setHidden:![mapSourcePicker isHidden]]; [mapView setUserInteractionEnabled:[mapSourcePicker isHidden]];}

And the main part is to change map source of the mapView object:

#import "RMVirtualEarthSource.h"#import "RMYahooMapSource.h"#import "RMCloudMadeMapSource.h"#import "RMOpenStreetMapsSource.h" #define CONST_MAP_KEY_bing @""#define CONST_MAP_KEY_cloud @"" - (void) setMapSourceWithNumber:(int)number{ if (mapSourceNumber == number)  returnswitch (number) {  case 0:   mapView.contents.tileSource = [[RMOpenStreetMapsSource alloc] init];   break;  case 1:   mapView.contents.tileSource = [[RMYahooMapSource alloc] init];    breakcase 2:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithAerialThemeUsingAccessKey:CONST_MAP_KEY_bing];    break;  case 3:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithHybridThemeUsingAccessKey:CONST_MAP_KEY_bing];    break;  case 4:   mapView.contents.tileSource = [[RMVirtualEarthSource alloc] initWithRoadThemeUsingAccessKey:CONST_MAP_KEY_bing];    breakcase 5:   mapView.contents.tileSource = [[RMCloudMadeMapSource alloc] initWithAccessKey:CONST_MAP_KEY_cloud styleNumber:1];   breakdefault:   return;   break; }  // this trick refreshs maps with new source [mapView moveBy:CGSizeMake(640,960)];  [mapView moveBy:CGSizeMake(-640,-960)];  mapSourceNumber = number; // remember user choice between runnings [[NSUserDefaults standardUserDefaults] setInteger:mapSourceNumber forKey:@"mapSourceNumber"];}

To obtain developer API key for Cloud Made and Virtual Earth (Bing) you need to register and submit a form:

The last thing I want to add is to remember what user chose during last app using. Let’s modify a viewDidLoad to:

- (void)viewDidLoad {    [super viewDidLoad][RMMapView class]; [mapView setDelegate:self]int number = [[NSUserDefaults standardUserDefaults] integerForKey:@"mapSourceNumber"]; [self setMapSourceWithNumber:number]; [mapSourcePicker selectRow:mapSourceNumber inComponent:0 animated:NO];} 

Note, selected map source number is stored to standartUserDefaults at end of setMapSourceWithNumber.

Map source UIPickerView (design)

Open IB to add:

  1. UIToolbar with one UIBarButtonItem connected to its IBOutlet
  2. connect an UIBarButtonItem press event with showMapsSettings IBAction
  3. UIPickerView above the map view and set it hidden 
  4. then connect an UIPickerView with IBOutlet and set its delegate and dataSource to the file’s owner

If you did all right and I did not forget something to describe you should have working app. Please run you application and campare to mine:

This sample is a part of my real application - Meeting Point. It’s free to download, try it.