14

I have setup an NSMutableArray of objects derived from a class that conforms to the MKAnnotation protocol. I have setup setup title and subtitle for the annotation and have successfully added them to the MKMapView using:

[[self customMapView] addAnnotations:locationArray];

What I want to do now is animate the pins dropping, initially I thought I could do that with Option1, using this everything works, but the pins don't do an animated drop.

// Option1
// WORKS FOR: pinColor YES, animatesDrop NO, LABEL YES
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    for(MKPinAnnotationView *eachView in views) {
        [eachView setAnimatesDrop:YES];
        [eachView setPinColor:MKPinAnnotationColorPurple];
    }
}

My next guess was to try Option2, this seems to work very well but I have two issues. The title and subtitle don't show up, my custom annotation object is getting passed in (I can see it in the debugger) but the information contained is not making it across to the new pin. Secondly this creates a new set of MKAnnotationViews, what happens to the old ones, are there and issues with memory leaks?

// Option2
//FOR: pinColor YES, animatesDrop YES, LABEL NO
- (MKAnnotationView *) mapView: (MKMapView *) mapView viewForAnnotation: (id<MKAnnotation>) annotation {
    MKPinAnnotationView *pin = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier: @"annotation_ID"];
    if (pin == nil) {
        pin = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: @"annotation_ID"] autorelease];
    } else {
        pin.annotation = annotation;
    }
    pin.pinColor = MKPinAnnotationColorRed;
    pin.animatesDrop = YES;
    return pin;
}

EDIT: I have solved the missing title & subTitle by adding pin.canShowCallout = YES;

fuzzygoat
  • 26,573
  • 48
  • 165
  • 294
  • 1
    In your option 2 code, when the pin is created it won't have the annotation set. I would remove the "else" and indent the pin.annotation = annotation line, so that it always gets set. – theLastNightTrain Dec 22 '11 at 10:31

3 Answers3

32

MKPinAnnotationView is a subclass of MKAnnotationView.

MKAnnotationView is a generic annotation view for which you have to provide the image and animation if desired.

MKPinAnnotationView is a convenient subclass of MKAnnotationView which automatically provides a pin image in a selected color and an animation of the pin dropping onto the map. You set the animatesDrop property when creating the view in viewForAnnotation and it will handle the animation automatically from there.

If you don't implement viewForAnnotation, a standard red pin with no animation is displayed.

By the time didAddAnnotationViews is called, the automatic animation has already happened and setting that property there has no effect.

If however you want to create a custom animation different from the default drop animation that MKPinAnnotationView provides, you could do that in didAddAnnotationViews. The view will already be at its final destination point so you save that and then animate it from a different point to that destination.

If you're happy with the default drop animation that MKPinAnnotationView provides, you don't need to implement didAddAnnotationViews. That delegate method is more useful for doing other things that you might need to do when all the annotation views are actually in place.

For your pins to show the title, set canShowCallout to YES where you set animatesDrop.

Not sure what you mean by "this creates a new set of MKAnnotationViews". In the viewForAnnotation method, you are providing a view (MKPinAnnotationView) for the MKAnnotation object. They are not the same thing.

Also, the viewForAnnotation method works like the cellForRowAtIndexPath method for UITableView where annotation views can get recycled which is why it's important to set MKAnnotation-specific information in the view every time (such as the annotation property).

  • Thank you aBitObvoius, a perfect answer. With regards to the MKAnnotationViews I was getting confused thinking that if you don't implement viewForAnnotation (where you get the default red pins) that maybe there already was a MKAnnotationView created somewhere and by subsequently implementing it I might need to do something with the old one. – fuzzygoat Jan 17 '11 at 17:00
  • Ok, by implementing viewForAnnotation, you are overriding the default view so there is no duplication. –  Jan 17 '11 at 17:04
11

Here's the most simple solution I could find. What it does is drops a single pin on the UIMapView in viewDidLoad event.

  1. The project references MapKit framework

  2. The view have the following import:#import <MapKit/MapKit.h>

  3. The view controller implements MKMapViewDelegate protocol

  4. The view controller implementation contains:

- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id ) annotation
{
    MKPinAnnotationView *newAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"annotation1"];
    newAnnotation.pinColor = MKPinAnnotationColorGreen;
    newAnnotation.animatesDrop = YES; 
    newAnnotation.canShowCallout = NO;
    [newAnnotation setSelected:YES animated:YES]; 
    return newAnnotation;
}
  1. The viewDidLoad contains:
CLLocationCoordinate2D geos = CLLocationCoordinate2DMake(0.2344, 45.324);
MKPlacemark* marker = [[MKPlacemark alloc] initWithCoordinate:geos addressDictionary:nil];
[mapView addAnnotation:marker];
[marker release];
mrt
  • 1,669
  • 3
  • 22
  • 32
  • 1
    In viewForAnnotation:, you are supposed to use mapView.dequeueReusableAnnotationViewWithIdentifier, the same way you would use dequeueReusableCellWithIdentifier in a tableView. Otherwise, you keep creating MKAnnotations with a reuse identifier that you don't actually reuse. – Frederic Adda Mar 22 '15 at 07:25
  • You select annotation within viewForAnnotation which seems rather senseless. – pronebird Dec 28 '16 at 16:10
0

Update Swift3:

 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

  if annotation is MKUserLocation {
     return nil
  }

  let pinAnnotation = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "PinAnnotation")
  pinAnnotation.pinTintColor = .green;
  pinAnnotation.animatesDrop = true;
  pinAnnotation.canShowCallout = false;
  pinAnnotation.setSelected(true, animated: true)

  return pinAnnotation
}
Shyam
  • 366
  • 1
  • 2
  • 10