iOS MapKit dragged annotations (MKAnnotationView) no longer pan with map

家住魔仙堡 提交于 2019-11-29 11:43:05

There are lots of examples about how to use the delegate method mapView:viewForAnnotation: that show setting up an MKAnnotationView. But what is not as obvious is that just because you set the draggable property of your MKAnnotationView instance to YES, you still have to write some code to help it transition some of the states. MapKit will take care of moving your instance's dragState to MKAnnotationViewDragStateStarting and MKAnnotationViewDragStateEnding, but it will not do the other transitions. You see hints of this in the docs notes about subclassing MKAnnotationView and the need to override the `setDragState:animated:'

When the drag state changes to MKAnnotationViewDragStateStarting, set the state to MKAnnotationViewDragStateDragging. If you perform an animation to indicate the beginning of a drag, and the animated parameter is YES, perform that animation before changing the state.

When the state changes to either MKAnnotationViewDragStateCanceling or MKAnnotationViewDragStateEnding, set the state to MKAnnotationViewDragStateNone. If you perform an animation at the end of a drag, and the animated parameter is YES, you should perform that animation before changing the state.

In this case, I'm not subclassing, but it seems that MKAnnotationView still struggles to make the transitions on its own. So you have to implement the delegate's mapView:annotationView:didChangeDragState:fromOldState: method. E.g.

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

This allows things to complete appropriately, so that when you pan the map after dragging the annotation, the annotation moves with the pan.

Are you using a custom map pin? I saw this before as well. Seems to be a bug in iOS 7. As a workaround, we just ended up using the default pin for MKPinAnnotationView.

Your setCoordinate was missing the required Key-Value observing methods (willChangeValueForKey/didChangeValueForKey) that are required for the map to detect when the annotation has been moved so it can move the annotation view to match, e.g.

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

Source: https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKAnnotation_Protocol/index.html#//apple_ref/occ/intfp/MKAnnotation/coordinate

"Your implementation of this property must be key-value observing (KVO) compliant. For more information on how to implement support for KVO, see Key-Value Observing Programming Guide."

Sorry Apple wasn't clear in the docs, what they meant to say was the setCoordinate requires the Key-Value observing methods willChangeValueForKey & didChangeValueForKey that allow the map to detect when the annotation has been moved so it can move the annotation view to match, e.g.

- (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"];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!