Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

SimonBS

macrumors regular
Original poster
Dec 30, 2009
202
0
Hi,

I found a short guide on how to load "annotation data" from a plist and add those annotations (pins) to a MapView.

My question is if anyone can tell me how I would customize the pins the most easily? As an example, I would like to define a color and an image in the plist and then have it set when adding the pins.

The pins are added like this:

MyAnnotation.m:

Code:
@implementation MyAnnotation
@synthesize title, subtitle, coordinate;

-(void) dealloc {
    [super dealloc];
    self.title = nil;
    self.subtitle = nil;
}

MyAnnotation.h

Code:
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MyAnnotation : NSObject<MKAnnotation> {
    CLLocationCoordinate2D coordinate;
    NSString *title;
    NSString *subtitle;
}

@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString* title;
@property (nonatomic, copy) NSString* subtitle;

Running through the plist in ViewDidLoad in MapViewController.m (array containg dictionaries for each pin) and adding annotations.

Code:
NSString *path = [[NSBundle mainBundle] pathForResource:@"Annotations" ofType:@"plist"];
    NSMutableArray* anns = [[NSMutableArray alloc] initWithContentsOfFile:path];

    for(int i = 0; i < [anns count]; i++) {
        float realLatitude = [[[anns objectAtIndex:i] objectForKey:@"latitude"] floatValue];
        float realLongitude = [[[anns objectAtIndex:i] objectForKey:@"longitude"] floatValue];

        MyAnnotation* myAnnotation = [[MyAnnotation alloc] init];
        CLLocationCoordinate2D theCoordinate;
        theCoordinate.latitude = realLatitude;
        theCoordinate.longitude = realLongitude;
        myAnnotation.coordinate = theCoordinate;
        myAnnotation.title = [[anns objectAtIndex:i] objectForKey:@"title"];
        myAnnotation.subtitle = [[anns objectAtIndex:i] objectForKey:@"subtitle"];
        [mapView addAnnotation:myAnnotation];
        [annotations addObject:myAnnotation];
        [myAnnotation release];
    }

EDIT:
I have added the viewForAnnotation method which sets the color but how can I set the color of each pin individually?

Code:
-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation {
	MKPinAnnotationView *pinView = nil;
	
	if(annotation != mapView.userLocation) {
		static NSString *defaultPinID = @"com.invasivecode.pin";
		pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
		if ( pinView == nil ) pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
		
		pinView.pinColor = MKPinAnnotationColorPurple; 
		pinView.canShowCallout = YES;
		pinView.animatesDrop = YES;
	} 
	else {
		[mapView.userLocation setTitle:@"I am here"];
	}
	
	return pinView;
}
 
Last edited:
I have added the viewForAnnotation method which sets the color but how can I set the color of each pin individually?
 
I believe you would do that in the viewForAnnotation method.... You are certainly allowed to return different MKAnnotationViews (with different colors) based on the annotation that you receive.
 
I believe you would do that in the viewForAnnotation method.... You are certainly allowed to return different MKAnnotationViews (with different colors) based on the annotation that you receive.

I just can't seem to find out how to "send the color" to viewForAnnotation and not hardcode it directly into the method.
 
You could make a helper method that you'd call from viewForAnnotation and pass it the annotation and have it return a color for that annotation.
 
Not sure if this helps since you are using the plist but... In the apple demo "MapCallouts" they color the pins by
Code:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    // if it's the user location, just return nil.
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;
    
    // handle our two custom annotations
    //
    if ([annotation isKindOfClass:[BridgeAnnotation class]]) // for Golden Gate Bridge
    {
        // try to dequeue an existing pin view first
        static NSString* BridgeAnnotationIdentifier = @"bridgeAnnotationIdentifier";
        MKPinAnnotationView* pinView = (MKPinAnnotationView *)
                                        [mapView dequeueReusableAnnotationViewWithIdentifier:BridgeAnnotationIdentifier];
        if (!pinView)
        {
            // if an existing pin view was not available, create one
            MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
                                             initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier] autorelease];
            [B]customPinView.pinColor = MKPinAnnotationColorPurple;[/B]
            customPinView.animatesDrop = YES;
            customPinView.canShowCallout = YES;
            
            // add a detail disclosure button to the callout which will open a new view controller page
            //
            // note: you can assign a specific call out accessory view, or as MKMapViewDelegate you can implement:
            //  - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control;
            //
            UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:self
                            action:@selector(showDetails:)
                  forControlEvents:UIControlEventTouchUpInside];
            customPinView.rightCalloutAccessoryView = rightButton;

            return customPinView;
        }
        else
        {
            pinView.annotation = annotation;
        }
        return pinView;
    }
    
    return nil;
}
 
Not sure if this helps since you are using the plist but... In the apple demo "MapCallouts" they color the pins by
Code:
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
    // if it's the user location, just return nil.
    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;
    
    // handle our two custom annotations
    //
    if ([annotation isKindOfClass:[BridgeAnnotation class]]) // for Golden Gate Bridge
    {
        // try to dequeue an existing pin view first
        static NSString* BridgeAnnotationIdentifier = @"bridgeAnnotationIdentifier";
        MKPinAnnotationView* pinView = (MKPinAnnotationView *)
                                        [mapView dequeueReusableAnnotationViewWithIdentifier:BridgeAnnotationIdentifier];
        if (!pinView)
        {
            // if an existing pin view was not available, create one
            MKPinAnnotationView* customPinView = [[[MKPinAnnotationView alloc]
                                             initWithAnnotation:annotation reuseIdentifier:BridgeAnnotationIdentifier] autorelease];
            [B]customPinView.pinColor = MKPinAnnotationColorPurple;[/B]
            customPinView.animatesDrop = YES;
            customPinView.canShowCallout = YES;
            
            // add a detail disclosure button to the callout which will open a new view controller page
            //
            // note: you can assign a specific call out accessory view, or as MKMapViewDelegate you can implement:
            //  - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control;
            //
            UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            [rightButton addTarget:self
                            action:@selector(showDetails:)
                  forControlEvents:UIControlEventTouchUpInside];
            customPinView.rightCalloutAccessoryView = rightButton;

            return customPinView;
        }
        else
        {
            pinView.annotation = annotation;
        }
        return pinView;
    }
    
    return nil;
}

Problem is that Apple is assigning ALL annotations with the same color - I would like to be able to have some annotations in green, some in red and some in purple.
 
Solved! It can be done like this:

Code:
for(MyAnnotation* a in mapView.annotations) {
			if(annotation == a && annotation != mapView.userLocation) {
				pinView.image = [UIImage imageNamed:a.annImage];
			}
		}
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.