This may sound like a generic question but I've only found answers if I want the same image for all my pins, which i don't.
That's how i'm working right now :
I have all my locations in an array of Locations (custom class with long, lat, name, pin name).
in the viewdidLoad I loop that array and create my pins with every object found, see following code :
for(int i = 0 ; i<[_locationList count] ; i++)
{
Location *item = [_locationList objectAtIndex:i];
CLLocationCoordinate2D coordinate;
coordinate.latitude = item.locationLatitude;
coordinate.longitude = item.locationLongitude;
NSString *title = item.locationName;
CustomAnnotation* ann = [CustomAnnotation new];
ann.name = title;
ann.coordinate = coordinate;
ann.pinName = [NSString stringWithFormat:@"pin%i.png",item.idPin];
[self.map addAnnotation:ann];
}
This is pretty straight forward, part from the CustomAnnotation class, which is the following code :
@interface CustomAnnotation : MKPointAnnotation <MKAnnotation>{
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *description;
@property (nonatomic, retain) NSString *pinName;
@end
This is all from stuff i've seen around the internet, and I kinda believe it's all correct up to that point.
In my mind, i'm still creating very classic pins, they just have one more property (pinName), which is why it's coming from the custom class.
Now, in the viewForAnnotation, i have absolutly NO IDEA how to tell it to get that pinName and use it.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.image = // I wanted to write annotation.pinName But it's just not that.
pinView.calloutOffset = CGPointMake(0, 32);
}else {
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
What am I missing? I'm obviously doing something wrong but i jsut can't figure it out, and i'm still quite confused with the differences between MKAnnotationsView & MKPointAnnotation & MKPinAnnotation, ...
More info : the pin names are " pinX.png ", X being a number between 1 and 12. I just want to use that name so the program can find it in the ressources where the picture lies.
Since your annotations are of type CustomAnnotation
, it would be more accurate to check if the annotations are of that kind instead of MKPointAnnotation
.
Then, casting the annotation
parameter to your custom class will let you easily access the custom properties in it like this:
CustomAnnotation *ca = (CustomAnnotation *)annotation;
pinView.image = [UIImage imageNamed:ca.pinName];
However, because the image can be different for each annotation, you should set it after the annotation view has been created or dequeued (not only in the if (!pinView)
block -- otherwise an annotation could end up re-using the view from another annotation no longer visible and the wrong image will show).
The updated method would look like this:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// If it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// Handle any custom annotations.
if ([annotation isKindOfClass:[CustomAnnotation class]])
{
// Try to dequeue an existing pin view first.
MKAnnotationView *pinView = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
if (!pinView)
{
// If an existing pin view was not available, create one.
pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"CustomPinAnnotationView"];
pinView.canShowCallout = YES;
pinView.calloutOffset = CGPointMake(0, 32);
//NOTE:
//If the calloutOffset needs to be different for each image,
//then this line should also be set below with the image.
}
else {
pinView.annotation = annotation;
}
//Set image on view AFTER we have a new or dequeued view
//because image is based on each annotation...
CustomAnnotation *ca = (CustomAnnotation *)annotation;
pinView.image = [UIImage imageNamed:ca.pinName];
//Might want to check that the UIImage is not nil
//in case pinName is invalid since that would result in
//an invisible annotation view. If the UIImage is nil,
//set pinView.image to some default image.
return pinView;
}
return nil;
}
For the confusion about the differences between the MapKit classes, see:
Should I use MKAnnotation, MKAnnotationView or MKPinAnnotation?. Even though that question is tagged MonoTouch, it still applies.
MKMapView, animateDrop? may also help.