0

I've been looking around for quite a bit and I haven't really found a good answer for this. I'm trying to change the color of the pin in a few different locations (1 red, 1 purple..)

I have a separate annotation class pinPlaceMark.h #import #import

@interface PinPlaceMark : NSObject <MKAnnotation>

@property(nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property(nonatomic, strong) NSString *myTitle;
@property(nonatomic, strong) NSString *mySubTitle;

- (id) initWithCoordinate: (CLLocationCoordinate2D) coordinate;
@end

pinPlaceMark.m

#import "PinPlaceMark.h"

@implementation PinPlaceMark

- (id) initWithCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
if (self)
{
    self.coordinate = coordinate;
}
return self;
}

- (NSString *) subtitle
{
return self.mySubTitle;
}

- (NSString *) title
{
return self.myTitle;
}
@end

mapViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "PinPlaceMark.h"
@interface MapViewController : UIViewController <MKMapViewDelegate>
@property (nonatomic, strong) IBOutlet MKMapView *mapView;

mapViewController.m

- (void) addPinWithCoordinate: (CLLocationCoordinate2D) pinLocation
{
PinPlaceMark *placeMark = [[PinPlaceMark alloc] initWithCoordinate:pinLocation];

placeMark.myTitle = @"This is my title";
placeMark.mySubTitle = @"This is my subtitle";

[self.mapView addAnnotation:placeMark];
}


- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate = self;
CLLocationCoordinate2D pinLocation1;
pinLocation1.latitude = 40.7101843;
pinLocation1.longitude = -74.0061474;
[self addPinWithCoordinate:pinLocation1];
}
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation 
    MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"id"];
pinView.pinColor = MKPinAnnotationColorPurple;
return pinView;

Just for one color. How do I go about changing the color in different locations Ive tried creating another instance of MKPinAnnotationView and returning it based on the coordinates, but its not working for me.

Thanks for any help you can provide.

MendyK
  • 1,643
  • 1
  • 17
  • 30
  • Can you give us some details of how your annotations are created and what their properties are? – pbasdf Sep 02 '14 at 18:48
  • 1
    See http://stackoverflow.com/questions/24215210/does-mkannotationview-buffer-its-input-queue. You don't really want to base the pin color "on the coordinates" literally but on some other distinct property of each annotation (you could just add a "pinColor" property to your PinPlaceMark class, set it when adding the annotation, and in viewForAnnotation set the view's pinColor from the annotation's pinColor property. –  Sep 02 '14 at 19:06
  • Can you give me some example code? – MendyK Sep 03 '14 at 16:59
  • The answer I linked to has sample code (so do the linked answers _inside_ that answer). Please try something from those and/or update your question with the revised code and the specific new problem. –  Sep 04 '14 at 11:27

3 Answers3

2

Here's an example of what I am suggesting...

First, add a pin color property to your custom annotation class PinPlaceMark so you can set the color of each pin individually. This property should be in the class that implements MKAnnotation (the model object). The property doesn't have to be "pin color" -- just some value specific to each annotation that will make it easy to decide what pin color to set the view to in viewForAnnotation:

@property (nonatomic, assign) MKPinAnnotationColor myPinColor;


Next, update your addPinWithCoordinate: method (because that's where you are creating instances of PinPlaceMark) to accept a pin color and set it:

- (void) addPinWithCoordinate:(CLLocationCoordinate2D)pinLocation 
                        color:(MKPinAnnotationColor)pinColor  //<-- new
{
    PinPlaceMark *placeMark = [[PinPlaceMark alloc] initWithCoordinate:pinLocation];

    placeMark.myTitle = @"This is my title";
    placeMark.mySubTitle = @"This is my subtitle";

    placeMark.myPinColor = pinColor;  //<-- new

    [self.mapView addAnnotation:placeMark];
}


Next, update the code that calls addPinWithCoordinate:. Example also shows multiple pins being added with different colors:

CLLocationCoordinate2D pinLocation1;
pinLocation1.latitude = 40.7101843;
pinLocation1.longitude = -74.0061474;
[self addPinWithCoordinate:pinLocation1 color:MKPinAnnotationColorGreen];

CLLocationCoordinate2D pinLocation2 = CLLocationCoordinate2DMake(41, -75);
[self addPinWithCoordinate:pinLocation2 color:MKPinAnnotationColorRed];

CLLocationCoordinate2D pinLocation3 = CLLocationCoordinate2DMake(32, -80);
[self addPinWithCoordinate:pinLocation3 color:MKPinAnnotationColorPurple];

CLLocationCoordinate2D pinLocation4 = CLLocationCoordinate2DMake(50, -90);
[self addPinWithCoordinate:pinLocation4 color:MKPinAnnotationColorGreen];

CLLocationCoordinate2D pinLocation5 = CLLocationCoordinate2DMake(40, -120);
[self addPinWithCoordinate:pinLocation5 color:MKPinAnnotationColorRed];

CLLocationCoordinate2D pinLocation6 = CLLocationCoordinate2DMake(45, -100);
[self addPinWithCoordinate:pinLocation6 color:MKPinAnnotationColorPurple];


Finally, update the viewForAnnotation delegate method to check if the annotation is of type PinPlaceMark and use its myPinColor property:

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
    if (! [annotation isKindOfClass:[PinPlaceMark class]]) {
        //if annotation is not a PinPlaceMark (eg. user location),
        //return nil so map view draws default view (eg. blue dot) for it...
        return nil;
    }

    static NSString *reuseId = @"id";

    MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
    if (pinView == nil) {
        pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
        pinView.canShowCallout = YES;
    }
    else {
        pinView.annotation = annotation;
    }

    //Set annotation-specific properties **AFTER**
    //view is dequeued or created...

    PinPlaceMark *ppm = (PinPlaceMark *)annotation;
    pinView.pinColor = ppm.myPinColor;

    return pinView;
}
  • Thanks so much for explaining it! Theres just one thing I dont really get (probably b/c im new to programming) in the line: 'MKPinAnnotationView *pinView = (MKPinAnnotationView *)' what exactly does the (MKPinAnnotationView *) do in this case? – MendyK Sep 05 '14 at 04:03
  • That's a type cast. The dequeueReusableAnnotationViewWithIdentifier method is defined as returning some view that is a subclass of MKAnnotationView. But we know we are only creating MKPinAnnotationView (a subclass of MKAnnotationView) objects and pinView is declared as that type. If we didn't type cast, the compiler would complain about a type mismatch but we're telling it "it's ok". –  Sep 05 '14 at 10:39
0

To achieve this you could possibly generate random colored images and assign it to MKPinAnnotationView. Though I haven't tried it on my MAC but it should work.

Below is source code for same:

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"id"];

// Code for random color 

CGFloat hue = ( arc4random() % 256 / 256.0 );  //  0.0 to 1.0
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from white
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5;  //  0.5 to 1.0, away from black
UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1];

UIImage * image = [self imageWithColor:color];
 UIImageView *imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
 [pinView addSubview:imageView];
return pinView;

}

- (UIImage *)imageWithColor:(UIColor *)color{

    CGRect rect = CGRectMake(0.0f, 0.0f, 10.0f, 10.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}
Paresh
  • 138
  • 1
  • 1
  • 8
  • Thanks for the code, but I was looking for something more basic. I just want to change the colors of different pins on the map, using the default ios colors. I'm a beginner and that delegate method "viewForAnnotation" is confusing – MendyK Sep 04 '14 at 14:43
  • "viewForAnnotation" is very basic delegate method of MKMapViewDelegate . Suppose you have n number of markers/ map pins to be plotted on map then this delegate method will get called n times. – Paresh Sep 04 '14 at 15:17
  • In what order? ...For some reason this is more confusing for me than all other delegate methods. – MendyK Sep 04 '14 at 15:26
  • Suppose you have an NSArray say annotations with n MKAnnotation objects added in it and you are calling [mkMapView addAnnotations:annotations]; Then addAnnotations will trigger "viewForAnnotation" delegate method and will get executed for n number of times as annotations has n MKAnnotation objects. It will plot markers in the order in which MKAnnotations are added to NSArray. – Paresh Sep 04 '14 at 15:43
  • For some reason i really dont get it. Thanks anyway for your help tho. – MendyK Sep 04 '14 at 16:58
  • @Paresh, Please note the `viewForAnnotation` delegate method is not necessarily called immediately after addAnnotation and definitely can be called multiple times for the same annotation (so "n annotations" does not always mean "n calls to viewForAnnotation"). This can happen if you pan/zoom the map and the annotations come back into view. There is also no guarantee of what order it will be called in. –  Sep 04 '14 at 21:40
  • @Anna Thanks a lot for sharing detailed things about "viewForAnnotation" delegate method – Paresh Sep 05 '14 at 05:37
0
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "MyAnnotation.h"
@interface MainViewController : UIViewController<MKMapViewDelegate>
{
    NSMutableArray *annotationArray;
    int i;
}
@property (weak, nonatomic) IBOutlet MKMapView *mapView;

@end
@implementation MainViewController

    @synthesize mapView;
        - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
    }
- (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.title=@"Machine Test";
    mapView.delegate=self;
        i=1;    //use for different colors of pins
   annotationArray = [[NSMutableArray alloc] init];
    // Do any additional setup after loading the view from its nib.

    //Annotation object1
        MyAnnotation *ann1 = [MyAnnotation new];
        ann1.title=@"Pune";
        ann1.subtitle=@"India";
        CLLocationCoordinate2D Cordinate1;
        Cordinate1.latitude = 18.;
        Cordinate1.longitude = 73.5;
        ann1.coordinate = Cordinate1;
        [annotationArray addObject:ann1];

    //Annotation object2
        MyAnnotation *ann2=[MyAnnotation new];
        ann2.title=@"Delhi";
        ann2.subtitle=@"India";
        CLLocationCoordinate2D Coordinate2;
        Coordinate2.latitude=25;
        Coordinate2.longitude=78;
        ann2.coordinate=Coordinate2;
        [annotationArray addObject:ann2];

    //Annotation object3
        MyAnnotation *ann3=[MyAnnotation new];
        ann3.title=@"Hyderabad";
        ann3.subtitle=@"India";
        CLLocationCoordinate2D Coordinate3;
        Coordinate3.latitude=18.5;
        Coordinate3.longitude=78;
        ann3.coordinate=Coordinate3;
        [annotationArray addObject:ann3];

    //Annotation Object4
        MyAnnotation *ann4=[MyAnnotation new];
        ann4.title=@"Himalaya";
        ann4.subtitle=@"India";
        CLLocationCoordinate2D Coordinate4;
        Coordinate4.latitude=28;
        Coordinate4.longitude=80;
        ann4.coordinate=Coordinate4;
        [annotationArray addObject:ann4];

    //Add all annotation objects in 1 array and pass for adding annotation
    [mapView addAnnotations:annotationArray];

    }
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{

    static NSString *AnnotationIdentifier = @"AnnotationIdentifier";
    MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier];
    pinView.animatesDrop = YES;
    pinView.canShowCallout = YES;
        if (i==1) {
            pinView.pinColor = MKPinAnnotationColorPurple;
            i++;
        }else if (i%2) {
            pinView.pinColor = MKPinAnnotationColorGreen;
            i++;
        }else{
            pinView.pinColor = MKPinAnnotationColorRed;
            i++;
        }
    return pinView;
}
- (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
@end;
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MyAnnotation : NSObject<MKAnnotation>
@property (copy, nonatomic)NSString *title;
@property (copy, nonatomic)NSString *subtitle;
@property (assign, nonatomic)CLLocationCoordinate2D coordinate;
@end

    objMain=[[MainViewController alloc]initWithNibName:@"MainViewController" bundle:nil];
    objNav=[[UINavigationController alloc]initWithRootViewController:objMain];
    [self.window addSubview:objNav.view];
deepa
  • 1
  • 1
    As good as it is to share/correct the code, it's also a good practice to leave some helpful text so that someone who is just going through can know for sure what corrective measures are. – Shamas S Mar 06 '15 at 13:26