iOS的MapKit拖动注解(MKAnnotationView)不再与地图平移
我正在学习在我刚刚起步的iOS应用程序中使用MapKit。 我正在使用一些模型实体作为注释(将<MKAnnotation>
协议添加到它们的头文件中)。 我也创build自定义MKAnnotationViews并将draggable
属性设置为YES
。
我的模型对象有一个location
属性,它是一个CLLocation*
。 为了符合<MKAnnotation>
协议,我向该对象添加了以下内容:
- (CLLocationCoordinate2D) coordinate { return self.location.coordinate; } - (void) setCoordinate:(CLLocationCoordinate2D)newCoordinate { CLLocation* newLocation = [[CLLocation alloc] initWithCoordinate: newCoordinate altitude: self.location.altitude horizontalAccuracy: self.location.horizontalAccuracy verticalAccuracy: self.location.verticalAccuracy timestamp: nil]; self.location = newLocation; } - (NSString*) title { return self.name; } - (NSString*) subtitle { return self.serialID; }
所以,我有4个必要的方法。 而且他们非常简单。 当我阅读MKAnnotationView
和@draggable
属性中的苹果文档时,它说:
将该属性设置为YES可使用户拖放注释。 如果是,则关联的注释对象也必须实现setCoordinate:方法。 该属性的默认值是NO。
在其他地方, MKAnnotation
文档说:
您的此属性的实现必须符合键值观察(KVO)。 有关如何实现对KVO的支持的更多信息,请参阅Key-Value Observing Programming Guide。
我已经阅读了这个(简短的)文件,对于我来说,我应该做些什么来完成这个任务,以至于我从我的location
属性中获得的coordinate
本身就是一个适当的属性。
但我相当确定它不能正常工作。 当我拖动销钉时,它会移动,但是当我平移地图时,它不再移动。
UPDATE
所以我试着玩股票MKPinAnnotationView。 要做到这一点,我只是注释掉了我的委托的mapView:viewForAnnotation:
方法。 我发现这些默认情况下不可拖动。 我将mapView:didAddAnnotationViews:
添加到我的委托中,将添加的视图的draggable
属性设置为YES
。
一旦这样configuration,Pin视图,如下面的John Estropia暗示,似乎工作正常。 我决定使用mapView:annotationView:didChangeDragState:fromOldState:
delegate hook来仔细看看发生了什么:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState { NSArray* states = @[@"None", @"Starting", @"Dragging", @"Cancelling", @"Ending"]; NSLog(@"dragStateChangeFrom: %@ to: %@", states[oldState], states[newState]); }
对于股票的引脚,会看到如下所示的日志输出:
2014-02-05 09:07:45.924 myValve[1781:60b] dragStateChangeFrom: None to: Starting 2014-02-05 09:07:46.249 myValve[1781:60b] dragStateChangeFrom: Starting to: Dragging 2014-02-05 09:07:47.601 myValve[1781:60b] dragStateChangeFrom: Dragging to: Ending 2014-02-05 09:07:48.006 myValve[1781:60b] dragStateChangeFrom: Ending to: None
这看起来很合理。 但是,如果切换到configuration的MKAnnotationView
,您将看到的输出如下所示:
2014-02-05 09:09:41.389 myValve[1791:60b] dragStateChangeFrom: None to: Starting 2014-02-05 09:09:45.451 myValve[1791:60b] dragStateChangeFrom: Starting to: Ending
它错过了两个转换,从开始到拖动,从结束到无。
所以我开始怀疑我需要做一些与属性不同的东西。 但是,我仍然为什么这不起作用感到沮丧。
更新2
我创build了自己的Annotation
对象来站在我的模型对象之间,它可以有一个属性coordinate
属性。 行为保持不变。 这似乎是与MKAnnotationView
东西。
有很多关于如何使用委托方法mapView:viewForAnnotation:
的示例mapView:viewForAnnotation:
显示设置MKAnnotationView
。 但是不太明显的是,仅仅因为你将MKAnnotationView
实例的draggable
属性设置为YES
,你仍然需要编写一些代码来帮助它转换一些状态。 MapKit将负责将实例的dragState
移动到MKAnnotationViewDragStateStarting
和MKAnnotationViewDragStateEnding
,但不会执行其他转换。 你可以在关于MKAnnotationView
的文档注释中看到这个提示,并且需要覆盖`setDragState:animated:'
当拖动状态更改为MKAnnotationViewDragStateStarting时,将状态设置为MKAnnotationViewDragStateDragging。 如果您执行animation以指示拖动的开始,并且animation参数为YES,则在更改状态之前执行该animation。
当状态更改为MKAnnotationViewDragStateCanceling或MKAnnotationViewDragStateEnding时,将状态设置为MKAnnotationViewDragStateNone。 如果在拖动结束时执行animation,并且animation参数为YES,则应在更改状态之前执行该animation。
在这种情况下,我不是MKAnnotationView
类,但似乎MKAnnotationView
仍然在努力自己做转换。 所以你必须实现委托的mapView:annotationView:didChangeDragState:fromOldState:
method。 例如
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState { if (newState == MKAnnotationViewDragStateStarting) { annotationView.dragState = MKAnnotationViewDragStateDragging; } else if (newState == MKAnnotationViewDragStateEnding || newState == MKAnnotationViewDragStateCanceling) { annotationView.dragState = MKAnnotationViewDragStateNone;} } }
这样可以正确地完成任务,以便在拖动注释后平移地图时,注释将随着平移移动。
你在使用自定义地图引脚吗? 我之前也看到了这个。 似乎是iOS 7中的一个错误。作为一个解决方法,我们刚刚结束了使用MKPinAnnotationView
的默认引脚。
您的setCoordinate缺less必要的键值观察方法(willChangeValueForKey / didChangeValueForKey),这是地图检测移动注释时需要的,因此它可以移动注解视图以匹配,例如
- (void) setCoordinate:(CLLocationCoordinate2D)newCoordinate { [self willChangeValueForKey:@"coordinate"]; CLLocation* newLocation = [[CLLocation alloc] initWithCoordinate: newCoordinate altitude: self.location.altitude horizontalAccuracy: self.location.horizontalAccuracy verticalAccuracy: self.location.verticalAccuracy timestamp: nil]; self.location = newLocation; [self didChangeValueForKey:@"coordinate"]; }
来源: https : //developer.apple.com/library/ios/documentation/MapKit/Reference/MKAnnotation_Protocol/index.html#//apple_ref/occ/intfp/MKAnnotation/coordinate
“你的这个属性的实现必须遵循键值观察(KVO)。关于如何实现对KVO的支持的更多信息,请参阅Key-Value Observing Programming Guide。
对不起,Apple在文档中并不清楚,他们的意思是说setCoordinate需要Key-Value观察方法willChangeValueForKey&didChangeValueForKey,它允许地图检测注释何时被移动,因此它可以移动注解视图以匹配,例如
- (void) setCoordinate:(CLLocationCoordinate2D)newCoordinate { [self willChangeValueForKey:@"coordinate"]; CLLocation* newLocation = [[CLLocation alloc] initWithCoordinate: newCoordinate altitude: self.location.altitude horizontalAccuracy: self.location.horizontalAccuracy verticalAccuracy: self.location.verticalAccuracy timestamp: nil]; self.location = newLocation; [self didChangeValueForKey:@"coordinate"]; }