Categories
Articles

XCode 4 IPhone Mountains of the USA Tutorial: Lesson 9 – Add Annotation to MapView


<== Lesson 8 || Overview ||

This lesson adds an annotation and pin on the map to better show the location of the mountain.

Detail View with MapView Annotation

MapAnnotation class is all that you need to get a pin on the map with an annotation above it.

However, you may want the annotation and pin to “drop in” or you might want to control the pin color. This requires a MKMapViewDelegate class and the viewForAnnotation method. In this method a MKPinAnnotationView object is created to embellish the annotation with more functionality as well as the “drop in” effect. The DetailViewController class will serve as the MKMapViewDelegate.

As you proceed through the steps, the code items not needed to “just show an annotation and pin” are identified for you so you can try an example without the special drop in effect. To summarize that approach in advance, you do not need to add the MKMapViewDelegate protocol to your DetailViewController.h file, you exclude the [mapView setDelegate:self]; line from the viewWillAppear method in the DetailViewContoller.m files and you will not need the viewForAnnotation method added in step 3.

Source Download

  1. Starting XCode 4 Project. This is the lesson 8 project completed.
  2. PHP and CSV Files. Script to read data file and selects by elevation and returns XML. See Lesson 2.
  3. Completed XCode 4 Project

[ad name=”Google Adsense”]

Step 1: DetailViewController.h – Add the MKMapViewDelegate Protocol
Download and uncompress the Starting XCode Project file and open in XCode.

Open the DetailViewController.h class and add line 3 to include the MapAnnotation header.

On line 6 you need to edit in the MKMapViewDelegate protocol. This line is needed only if you want more functionality over the annotation such as pin color or a “drop in” effect by including the viewForAnnotation method.

#import &amp;amp;lt;UIKit/UIKit.h&amp;amp;gt;
#import &amp;amp;lt;MapKit/Mapkit.h&amp;amp;gt;
#import "MapAnnotation.h"
#import "MountainItem.h"

@interface DetailViewController : UIViewController &amp;amp;lt;MKMapViewDelegate&amp;amp;gt;{
    MKMapView *mapView;

    MountainItem *mountainItem;
}

@property (nonatomic, retain) IBOutlet MKMapView *mapView;

@property (nonatomic, retain) MountainItem *mountainItem;

@end

Step 2: DetailViewController.m – Create the Annotation
Open the DetailViewController.m file.

The first 51 lines of code are not changing but included here for online reference:

#import "DetailViewController.h"

@implementation DetailViewController
@synthesize mapView;
@synthesize mountainItem;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)dealloc
{
    [mapView dealloc];
    [super dealloc];
}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
    self.mapView = nil;

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

Add the highlighed line in the next code view.

Line 68 sets this class to receive MKMapViewDelegate messages. In the last step you defined this class as MKMapViewDelegate.

Line 68 is not needed if all you want to show the annotation and pin without any special view or effects. A MKMapViewDelegate is not needed for that.

Line 70 clears all annotations from the map. You can leave this line out and the previous pins and their annotations will stay on the map. If you try some mountains in the same range or zoom way out, you will see the previous pins and when you touch the pin the annotation will appear.

Lines 71 to 73 create the annotation object, give it a title and position in the center of the view region created in the last lesson on lines 61 to 66.

The annotation is added to the map on line 75.

The annotation is selected on line 77. When you test the app, you should touch the annotation and the pin. You will see the selected and unselected state. Unselected, just a pin appears. Selected the title appears. Line 77 is achieving the selection process in code.

Line 78 is clean up.

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [self setTitle:mountainItem.name];

    [mapView setMapType:MKMapTypeStandard];
    [mapView setZoomEnabled:YES];
    [mapView setScrollEnabled:YES];
    MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
    region.center.latitude = [mountainItem.latitude doubleValue] ;
    region.center.longitude = [mountainItem.longitude doubleValue] ;
    region.span.longitudeDelta = 1.0f;
    region.span.latitudeDelta = 1.0f;
    [mapView setRegion:region animated:YES];

    [mapView setDelegate:self];

    [self.mapView removeAnnotations:self.mapView.annotations];
    MapAnnotation *ann = [[MapAnnotation alloc] init];
    ann.title = mountainItem.name;
    ann.coordinate = region.center;

    [mapView addAnnotation:ann];

    [mapView selectAnnotation:ann animated:YES];
    [ann release];
}

[ad name=”Google Adsense”]

Step 3: DetailViewController.m – Add Annotation View and Drop In Effect

The viewForAnnotation method is called to develop the view for an annotation.

This implementation is simple because we only have one annotation. The method is called for all annotations. With multiple annotation, you may need to treat certain annotations differently, so you might need to identify which is calling this method. As well if you are using a unpredictable number of annotations and some annotations persist, this is a place to determine how to reuse MKPinAnnotationView objects. All of this is beyond the scope of the tutorial, but this explains why you will see more lines of code in other examples and why this example appears simpler.

Line 83 creates the MKPinAnnotationView annView object. You are going to reuse the same MKPinAnnotationView, so the identifier MyPin is created to help that happen.

The pin “drop in” effect occurs because of line 84.

Line 85 is needed to show the pin annotation title. There are more items that can be added to the annotation such as a subtitle and left and right views.

The pin color is set on line 87. You can use MKPinAnnotationColorGreen and MKPinAnnotationColorPurple. These and MKPinAnnotationColorRed were added in IOS 3.0.

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id &amp;amp;lt;MKAnnotation&amp;amp;gt;) annotation

{
    MKPinAnnotationView *annView = [[[MKPinAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier:@"MyPin"] autorelease] ;
    annView.animatesDrop=TRUE;
    annView.canShowCallout = YES;

	annView.pinColor = MKPinAnnotationColorRed;

    return annView;
}

Try in the simulator. Tap the annotations and the pins to get the feel for them.