How do I animate MKAnnotationView drop?

DeShawnT picture DeShawnT · Jul 24, 2011 · Viewed 17.3k times · Source

I have a custom MKAnnotationView where I set my image myself in viewForAnnotation. How do I animate it's drop like I can with MKPinAnnotationView?

My code is

- (MKAnnotationView *)mapView:(MKMapView *)map viewForAnnotation:(id <MKAnnotation>)annotation
{
    static NSString *AnnotationViewID = @"annotationViewID";

    MKAnnotationView *annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationViewID];

    if (annotationView == nil)
    {
        annotationView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID] autorelease];
    }

    annotationView.image = [UIImage imageNamed:@"blah.png"];
    annotationView.annotation = annotation;

    return annotationView;
}

Answer

MrAlek picture MrAlek · Aug 12, 2011

One problem with the code above by Anna Karenina is that it doesn't deal with when you add annotations below where the user is looking at the moment. Those annotations will float in mid-air before dropping because they are moved into the user's visible map rect.

Another is that it also drops the user location blue dot. With this code below, you handle both user location and large amounts of map annotations off-screen. I've also added a nice bounce ;)

- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    MKAnnotationView *aV; 

    for (aV in views) {

        // Don't pin drop if annotation is user location
        if ([aV.annotation isKindOfClass:[MKUserLocation class]]) {
            continue;
        }

        // Check if current annotation is inside visible map rect, else go to next one
        MKMapPoint point =  MKMapPointForCoordinate(aV.annotation.coordinate);
        if (!MKMapRectContainsPoint(self.mapView.visibleMapRect, point)) {
            continue;
        }

        CGRect endFrame = aV.frame;

        // Move annotation out of view
        aV.frame = CGRectMake(aV.frame.origin.x, aV.frame.origin.y - self.view.frame.size.height, aV.frame.size.width, aV.frame.size.height);

        // Animate drop
        [UIView animateWithDuration:0.5 delay:0.04*[views indexOfObject:aV] options: UIViewAnimationOptionCurveLinear animations:^{

            aV.frame = endFrame;

        // Animate squash
        }completion:^(BOOL finished){
            if (finished) {
                [UIView animateWithDuration:0.05 animations:^{
                    aV.transform = CGAffineTransformMakeScale(1.0, 0.8);

                }completion:^(BOOL finished){
                    if (finished) {
                        [UIView animateWithDuration:0.1 animations:^{
                            aV.transform = CGAffineTransformIdentity;
                        }];
                    }
                }];
            }
        }];
    }
}