如何为MKAnnotationView动画制作动画?

时间:2011-07-24 18:45:13

标签: cocoa-touch ios-4.2 mkannotationview mkpinannotationview mapkit

我有一个自定义的MKAnnotationView,我自己在viewForAnnotation中设置我的图像。我如何使用MKPinAnnotationView设置它的动画效果?

我的代码是

- (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;
}

7 个答案:

答案 0 :(得分:57)

Anna Karenina上面的代码存在的一个问题是,当您在用户正在查看的位置下方添加注释时,它不会处理。这些注释会在下降之前浮动在半空中,因为它们会被移动到用户的可见地图中。

另一个是它也会丢弃用户位置蓝点。使用下面的代码,您可以在屏幕外处理用户位置和大量地图注释。我也加了一个漂亮的反弹;)

- (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;
                        }];
                    }
                }];
            }
        }];
    }
}

答案 1 :(得分:47)

实施didAddAnnotationViews委托方法并自行动画:

- (void)mapView:(MKMapView *)mapView 
          didAddAnnotationViews:(NSArray *)annotationViews
{
    for (MKAnnotationView *annView in annotationViews)
    {
        CGRect endFrame = annView.frame;
        annView.frame = CGRectOffset(endFrame, 0, -500);
        [UIView animateWithDuration:0.5 
                animations:^{ annView.frame = endFrame; }];
    }
}

答案 2 :(得分:7)

@ MrAlek&#39;答案 swift3

optional func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
    print(#function)

    var i = -1;
    for view in views {
        i += 1;
        if view.annotation is MKUserLocation {
            continue;
        }

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

        let endFrame:CGRect = view.frame;

        // Move annotation out of view
        view.frame = CGRect(origin: CGPoint(x: view.frame.origin.x,y :view.frame.origin.y-self.view.frame.size.height), size: CGSize(width: view.frame.size.width, height: view.frame.size.height))

        // Animate drop
        let delay = 0.03 * Double(i)
        UIView.animate(withDuration: 0.5, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations:{() in
            view.frame = endFrame
            // Animate squash
            }, completion:{(Bool) in
                UIView.animate(withDuration: 0.05, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations:{() in
                    view.transform = CGAffineTransform(scaleX: 1.0, y: 0.6)

                    }, completion: {(Bool) in
                        UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions.curveEaseInOut, animations:{() in
                            view.transform = CGAffineTransform.identity
                            }, completion: nil)
                })

        })
    }
}

答案 3 :(得分:5)

@mrAlek回答Swift:

func mapView(mapView: MKMapView!, didAddAnnotationViews views: [AnyObject]!) {
    println("didAddAnnotationViews()")

    var i = -1;
    for view in views {
        i++;
        let mkView = view as! MKAnnotationView
        if view.annotation is MKUserLocation {
            continue;
        }

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

        let endFrame:CGRect = mkView.frame;

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

        // Animate drop
        let delay = 0.03 * Double(i)
        UIView.animateWithDuration(0.5, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations:{() in
            mkView.frame = endFrame
            // Animate squash
            }, completion:{(Bool) in
                        UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations:{() in
                            mkView.transform = CGAffineTransformMakeScale(1.0, 0.6)

                        }, completion: {(Bool) in
                                UIView.animateWithDuration(0.3, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations:{() in
                                    mkView.transform = CGAffineTransformIdentity
                                    }, completion: nil)
                        })

                    })
    }
}

答案 4 :(得分:5)

@ MrAlek在Swift 2中的回答:

func mapView(mapView: MKMapView, didAddAnnotationViews views: [MKAnnotationView]) {
    print(__FUNCTION__)

    var i = -1;
    for view in views {
        i++;
        if view.annotation is MKUserLocation {
            continue;
        }

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

        let endFrame:CGRect = view.frame;

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

        // Animate drop
        let delay = 0.03 * Double(i)
        UIView.animateWithDuration(0.5, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations:{() in
            view.frame = endFrame
            // Animate squash
            }, completion:{(Bool) in
                UIView.animateWithDuration(0.05, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations:{() in
                    view.transform = CGAffineTransformMakeScale(1.0, 0.6)

                    }, completion: {(Bool) in
                        UIView.animateWithDuration(0.3, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations:{() in
                            view.transform = CGAffineTransformIdentity
                            }, completion: nil)
                })

        })
    }
}

答案 5 :(得分:1)

已为Swift 4.2更新

   func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
    var i = -1;
    for view in views {
        i += 1;
        if view.annotation is MKUserLocation {
            continue;
        }
        let point:MKMapPoint  =  MKMapPoint(view.annotation!.coordinate);
        if (!self.mapView.visibleMapRect.contains(point)) {
            continue;
        }
        let endFrame:CGRect = view.frame;
        view.frame = CGRect(origin: CGPoint(x: view.frame.origin.x,y :view.frame.origin.y-self.view.frame.size.height), size: CGSize(width: view.frame.size.width, height: view.frame.size.height))
        let delay = 0.03 * Double(i)
        UIView.animate(withDuration: 0.5, delay: delay, options: UIView.AnimationOptions.curveEaseIn, animations:{() in
            view.frame = endFrame
        }, completion:{(Bool) in
            UIView.animate(withDuration: 0.05, delay: 0.0, options: UIView.AnimationOptions.curveEaseInOut, animations:{() in
                view.transform = CGAffineTransform(scaleX: 1.0, y: 0.6)
            }, completion: {(Bool) in
                UIView.animate(withDuration: 0.3, delay: 0.0, options: UIView.AnimationOptions.curveEaseInOut, animations:{() in
                    view.transform = CGAffineTransform.identity
                }, completion: nil)
            })
        })
    }
}

答案 6 :(得分:0)

除了在while (*(c+2) != '\0') { 中实现mapView(_:didAdd:)之外,还可以使注释视图自己制作动画。

MKMapViewDelegate

这对于避免使用注释视图动画的视图控制器造成混乱是很有用的。例如。在iOS 11及更高版本中,您可以这样做:

class CustomAnnotationView: MKAnnotationView {
    override var annotation: MKAnnotation? { didSet { update(for: annotation) } }

    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        update(for: annotation)
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        removeFromSuperview()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func didMoveToSuperview() {
        super.didMoveToSuperview()

        transform = CGAffineTransform(translationX: 0, y: -100)
        alpha = 0
        UIViewPropertyAnimator(duration: 0.5, dampingRatio: 0.4) {
            self.transform = .identity
            self.alpha = 1
        }.startAnimation()
    }

    private func update(for annotation: MKAnnotation?) {
        // do whatever update to the annotation view you want, if any
    }
}

然后您可以将注释添加到地图视图中,而无需在视图控制器中添加任何代码即可获得注释视图的动画。

这个特殊的动画是最后一滴有一点反弹的水滴,但是显然您可以做任何想要的动画。

以上内容是用Swift编写的,但该概念在Objective-C中同样有效。