2010-09-09 67 views
9

这是关于使用MKMapKit的iPhone应用程序:子类MKAnnotationView和压倒一切的setDragState

我创建了一个自定义的MKAnnotationView的可拖动注释。我想创建一个自定义动画。我设置自定义图钉图像和注释是可拖动(其中两个是这里没有显示,它的MapView发生)用下面的代码:

- (void) movePinUpFinished { 

    [super setDragState:MKAnnotationViewDragStateDragging]; 
    [self setDragState:MKAnnotationViewDragStateDragging]; 
} 

- (void) setDragState:(MKAnnotationViewDragState) myState { 
    if (myState == MKAnnotationViewDragStateStarting) { 
      NSLog(@"starting"); 
      CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
      self.center = endPoint; 
      [self movePinUpFinished]; 
    } 
    if (myState == MKAnnotationViewDragStateEnding) { 
      NSLog(@"ending"); 
      [super setDragState:MKAnnotationViewDragStateEnding]; 
      [self setDragState:MKAnnotationViewDragStateNone]; 
      [super setDragState:MKAnnotationViewDragStateNone]; 
    } 
    if (myState == MKAnnotationViewDragStateDragging) { 
      NSLog(@"dragging"); 
    } 
    if (myState == MKAnnotationViewDragStateCanceling) { 
      NSLog(@"cancel"); 
    } 
    if (myState == MKAnnotationViewDragStateNone) { 
      NSLog(@"none"); 
    } 
} 

一切工作正常,注释向上移动了一下,是可拖动,当我释放注释时,mapview会收到“dragstateending”。

但现在我希望动画运行在一段时间内,改变dragStateStarting以下几点:

if (myState == MKAnnotationViewDragStateStarting) { 
      NSLog(@"starting"); 
      CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
      [UIView animateWithDuration:1.0 
      animations:^{ self.center = endPoint; } 
      completion:^(BOOL finished){ [self movePinUpFinished]; }]; 
    } 

的动画运行通缉了第二期和注释拖动。但是当我释放注释时,mapview没有通过委托来接收结尾。我也认识到,当我在开始拖动之后以“UIView animateWithDuration ...”进行动画时,随着动画开始,注释的气球开启。当我在没有动画的情况下设置新中心时,气球保持关闭状态,只有在释放注释完成拖动后才能打开气球。

我在做什么错?这是覆盖setDragState的正确方法。我真的不得不打电话给超级班吗?但是,如果没有在超类中设置dragstate,我的mapview没有意识到dragstate的变化。

我想知道MKPinAnnotationView的原始实现,但是因为它是一个内部类,我无法找到setDragState方法的描述。

Thx寻求帮助。欢呼声中,

回答

23

我有脚拖工作,但试图弄清楚为什么发生的时候,你不会覆盖setDragState销annimations - 不再在我的实施工作。你的问题包含我的答案..谢谢!

你的代码的部分问题是,一旦你重写了setDragState函数,根据xcode文档,你将负责根据新的状态更新dragState变量。我也会有点担心你的代码调用自己(setDragState调用[self setDragState])。

这是我结束了(伴随着你的帮助)的代码,它完成了所有的升降机,拖拽和下降,因为我期望它们发生。希望这也能帮助你!

- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated 
{ 
    if (newDragState == MKAnnotationViewDragStateStarting) 
    { 
     // lift the pin and set the state to dragging 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
          { self.dragState = MKAnnotationViewDragStateDragging; }]; 
    } 
    else if (newDragState == MKAnnotationViewDragStateEnding) 
    { 
     // save the new location, drop the pin, and set state to none 

     /* my app specific code to save the new position 
     objectObservations[ACTIVE].latitude = pinAnnotation.coordinate.latitude; 
     objectObservations[ACTIVE].longitude = pinAnnotation.coordinate.longitude; 
     posChanged = TRUE; 
     */ 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
          { self.dragState = MKAnnotationViewDragStateNone; }]; 
    } 
    else if (newDragState == MKAnnotationViewDragStateCanceling) 
    { 
     // drop the pin and set the state to none 

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

它是如何完美运作的?当您将该引脚拖到屏幕外时,会导致崩溃。 – akshay1188 2012-01-13 08:24:19

+0

这有效,但有一件事让我感到困惑:在我的MKMapViewDelegate中,我重写了mapView:annotationView:didChangeDragState。 MKAnnotationView基类产生两个转换:拖动开始时从0-> 1,当结束时从1-> 4。上述解决方案似乎遵循苹果公司对T的指导原则,但它会产生0→2和2→0的转换。我可以忍受它,但它很奇怪 - 我认为苹果公司的文档是关闭的,说实话。 – n13 2012-03-17 08:38:27

+1

我想你需要调用'self.dragState = ...',而不是'dragState ='。否则,KVO通知将不会发送,并且地图视图不会看到拖动状态更改。 – Rick 2012-08-03 03:52:44

2

我没有研究Ben的代码,但它没有为我工作。所以我尝试了Brian's,它效果很好。非常感谢!我一直试图在很长一段时间拖放注释的动画。

但是我有一个建议Brian的解决方案。我认为最好是支持MKMapKit的委托并通知它关于更改dragState并在标准委托方法中保存新位置:- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState。这里是我的代码:

DraggableAnnotationView。H:

#import <Foundation/Foundation.h> 
#import <MapKit/MapKit.h> 

@interface DraggableAnnotationView : MKAnnotationView 
{ 
    id <MKMapViewDelegate> delegate; 
    MKAnnotationViewDragState dragState; 
} 

@property (nonatomic, assign) id <MKMapViewDelegate> delegate; 
@property (nonatomic, assign) MKAnnotationViewDragState dragState; 
@property (nonatomic, assign) MKMapView *mapView; 

@end 

DraggableAnnotationView.m:

#import "DraggableAnnotationView.h" 
#import "MapAnnotation.h" 

@implementation DraggableAnnotationView 
@synthesize delegate, dragState, mapView; 



- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated 
{ 
    [delegate mapView:mapView annotationView:self didChangeDragState:newDragState fromOldState:dragState]; 

    if (newDragState == MKAnnotationViewDragStateStarting) { 
     // lift the pin and set the state to dragging 
     CGPoint endPoint = CGPointMake(self.center.x,self.center.y-20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
     { dragState = MKAnnotationViewDragStateDragging; }]; 
    } else if (newDragState == MKAnnotationViewDragStateEnding) { 
     // drop the pin, and set state to none 

     CGPoint endPoint = CGPointMake(self.center.x,self.center.y+20); 
     [UIView animateWithDuration:0.2 
         animations:^{ self.center = endPoint; } 
         completion:^(BOOL finished) 
     { dragState = MKAnnotationViewDragStateNone; }]; 
    } else if (newDragState == MKAnnotationViewDragStateCanceling) { 
     // drop the pin and set the state to none 

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

- (void)dealloc 
{ 
    [super dealloc]; 
} 

@end 
+0

当我们将销钉拖到视图的边缘时,它会崩溃,我们的手指滑出屏幕。 – akshay1188 2012-01-13 08:35:07

3

虽然Brian's solution工作,但它缺乏考虑到用户的手指阻断正被操纵的注释图。

这意味着用户无法在拖动它时精确放置该引脚。标准的MKPinAnnotationView在这方面做得很好,发生的情况是当手指开始拖动时,将销钉抬起到手指上方,并且销钉的视觉点用于放置而不是之前位于手指下方的中心点。

除此之外,我的实现还添加了另一个动画,在拖动后释放引脚时,通过提升引脚并以更高的速度释放引脚。这与本地用户体验非常接近,并且会受到用户的推崇。

请查看我的gist on GitHub for the code

真的很酷的是设置一个委托是可选的,可选的,当注解视图被放回到地图上时发送一个通知。

+1

这个实现比其他答案更接近Apple的行为。好东西,谢谢! – 2012-10-27 03:39:47

+0

#import和@interface名称中存在一些拼写错误,但它们很容易修复。做得好。谢谢! – demosten 2013-05-11 18:58:26

+0

那真是令人尴尬,现在修复它。感谢您的支持 – Daniel 2013-05-11 22:00:02