[ios]MKAnnotationView 拖状态结束动画

标签: mapkit ios
发布时间: 2017/3/28 20:49:14
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.

我使用的由丹尼尔在这里提供的自定义 MKAnnotationView 动画︰子类化 MKAnnotationView 和压倒一切的 setDragState ,但是我遇到的问题。

Pin 滴动画过后时候移动地图, mkannotationview 跳回至其以前的位置之前最后针滴动画块叫做。

我看来,那 dragState = MKAnnotationViewDragStateEnding 被称为在动画运行之前吗?如何解决这个问题并设置 mkannotationview 的点,它是在动画结束时的最后一点?

#import "MapPin.h"

NSString *const DPAnnotationViewDidFinishDrag = @"DPAnnotationViewDidFinishDrag";
NSString *const DPAnnotationViewKey = @"DPAnnotationView";

// Estimate a finger size
// This is the amount of pixels I consider
// that the finger will block when the user
// is dragging the pin.
// We will use this to lift the pin even higher during dragging

#define kFingerSize 20.0

@interface MapPin()
@property (nonatomic) CGPoint fingerPoint;
@end

@implementation MapPin
@synthesize dragState, fingerPoint, mapView;

- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
    if(mapView){
        id<MKMapViewDelegate> mapDelegate = (id<MKMapViewDelegate>)mapView.delegate;
        [mapDelegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState];
    }

    // Calculate how much to life the pin, so that it's over the finger, no under.
    CGFloat liftValue = -(fingerPoint.y - self.frame.size.height - kFingerSize);

    if (newDragState == MKAnnotationViewDragStateStarting)
    {
        CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
        [MapPin animateWithDuration:0.2
                         animations:^{
                             self.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             dragState = MKAnnotationViewDragStateDragging;
                         }];

    }
    else if (newDragState == MKAnnotationViewDragStateEnding)
    {
        // lift the pin again, and drop it to current placement with faster animation.

        __block CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
        [MapPin animateWithDuration:0.2
                         animations:^{
                             self.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             endPoint = CGPointMake(self.center.x,self.center.y+liftValue);
                             [MapPin animateWithDuration:0.1
                                              animations:^{
                                                  self.center = endPoint;
                                              }
                                              completion:^(BOOL finished){
                                                  dragState = MKAnnotationViewDragStateNone;
                                                  if(!mapView)
                                                      [[NSNotificationCenter defaultCenter] postNotificationName:DPAnnotationViewDidFinishDrag object:nil userInfo:[NSDictionary dictionaryWithObject:self.annotation forKey:DPAnnotationViewKey]];
                                              }];
                         }];
    }
    else if (newDragState == MKAnnotationViewDragStateCanceling)
    {
        // drop the pin and set the state to none

        CGPoint endPoint = CGPointMake(self.center.x,self.center.y+liftValue);
        [UIView animateWithDuration:0.2
                         animations:^{
                             self.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             dragState = MKAnnotationViewDragStateNone;
                         }];
    }
}

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    // When the user touches the view, we need his point so we can calculate by how
    // much we should life the annotation, this is so that we don't hide any part of
    // the pin when the finger is down.

    fingerPoint = point;
    return [super hitTest:point withEvent:event];
}

@end

解决方法 1:

我有同样的问题,特别是在 iOS 8 下。经过许多小时的测试,我相信那 iOS 跟踪在它认为 self.center 的注释是期间的状态是 MKAnnotationViewDragStateDragging 。你需要格外小心,如果你进行动画处理 self.center 处理时 MKAnnotationViewDragStateEnding 。读,就像"我不能把那工作过。

处理状态相反,保持丹尼尔的原始代码 MKAnnotationViewDragStateStartingMKAnnotationViewDragStateCanceling ,我的动画 self.center 。 当处理 MKAnnotationViewDragStateEnding 我动画 self.transform 而不是 self.center 。 这保持注释的实际位置,只是改变了它的呈现方式。

这很适合我运行 iOS 7.1 和 iOS 8.0。 此外修正了一个在 hitTest ,并添加一些代码来重新选择后拖动或取消注释。 这是默认行为的 MKPinAnnotationView

- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated
{
    if(mapView){
        id<MKMapViewDelegate> mapDelegate = (id<MKMapViewDelegate>)mapView.delegate;
        [mapDelegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState];
    }

    // Calculate how much to lift the pin, so that it's over the finger, not under.
    CGFloat liftValue = -(fingerPoint.y - self.frame.size.height - kFingerSize);

    if (newDragState == MKAnnotationViewDragStateStarting)
    {
        CGPoint endPoint = CGPointMake(self.center.x,self.center.y-liftValue);
        [UIView animateWithDuration:0.2
                         animations:^{
                             self.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             dragState = MKAnnotationViewDragStateDragging;
                         }];

    }
    else if (newDragState == MKAnnotationViewDragStateEnding)
    {
        CGAffineTransform theTransform = CGAffineTransformMakeTranslation(0, -liftValue);
        [UIView animateWithDuration:0.2
                         animations:^{
                             self.transform = theTransform;
                         }
                         completion:^(BOOL finished){
                             CGAffineTransform theTransform2 = CGAffineTransformMakeTranslation(0, 0);
                             [UIView animateWithDuration:0.2
                                              animations:^{
                                                  self.transform = theTransform2;
                                              }
                                              completion:^(BOOL finished){
                                                  dragState = MKAnnotationViewDragStateNone;
                                                  if(!mapView)
                                                      [[NSNotificationCenter defaultCenter] postNotificationName:DPAnnotationViewDidFinishDrag object:nil userInfo:[NSDictionary dictionaryWithObject:self.annotation forKey:DPAnnotationViewKey]];
                                                  // Added this to select the annotation after dragging.
                                                  // This is the behavior for MKPinAnnotationView
                                                  if (mapView)
                                                      [mapView selectAnnotation:self.annotation animated:YES];
                                              }];
                         }];
    }
    else if (newDragState == MKAnnotationViewDragStateCanceling)
    {
        // drop the pin and set the state to none
        CGPoint endPoint = CGPointMake(self.center.x,self.center.y+liftValue);

        [UIView animateWithDuration:0.2
                         animations:^{
                             self.center = endPoint;
                         }
                         completion:^(BOOL finished){
                             dragState = MKAnnotationViewDragStateNone;
                             // Added this to select the annotation after canceling.
                             // This is the behavior for MKPinAnnotationView
                             if (mapView)
                                 [mapView selectAnnotation:self.annotation animated:YES];
                         }];
    }
}

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event
{
    // When the user touches the view, we need his point so we can calculate by how 
    // much we should life the annotation, this is so that we don't hide any part of
    // the pin when the finger is down.

    // Fixed a bug here.  If a touch happened while the annotation view was being dragged
    // then it screwed up the animation when the annotation was dropped.
    if (dragState == MKAnnotationViewDragStateNone)
    {
        fingerPoint = point;
    }
    return [super hitTest:point withEvent:event];
}
赞助商