iOS Swift MapKit making an annotation draggable by the user?
Asked Answered
D

1

16

How do I make it possible, using MapKit in Swift, for the user to drag an annotation from one position to another within the map? I have set the annotation view to be draggable, when my map view delegate creates the annotation view, like this:

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    var v : MKAnnotationView! = nil
    if annotation is MyAnnotation {
        let ident = "bike"
        v = mapView.dequeueReusableAnnotationView(withIdentifier:ident)
        if v == nil {
            v = MyAnnotationView(annotation:annotation, reuseIdentifier:ident)
        }
        v.annotation = annotation
        v.isDraggable = true
    }
    return v
}

The result is that the user can sort of drag the annotation - but only once. After that, the annotation becomes impossible to drag, and even worse, the annotation now no longer "belongs" to map - when the map is scrolled / panned, the annotation holds still rather than scrolling / panning with the map. What am I doing wrong?

Dramatize answered 21/4, 2015 at 15:38 Comment(0)
D
29

It isn't enough to mark the annotation view by setting isDraggable to true. You must also implement mapView(_:annotationView:didChange:fromOldState:) in your map view delegate - and (even more important) this implementation must not be empty! Rather, your implementation must, at a minimum, communicate the drag state from the incoming parameters to the annotation view, like this:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, didChange newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
    switch newState {
    case .starting:
        view.dragState = .dragging
    case .ending, .canceling:
        view.dragState = .none
    default: break
    }
}

Once you do that, the annotation will be properly draggable by the user.

(Many thanks to this answer for explaining this so clearly. I can't claim any credit! My answer here is merely a translation of that code into Swift.)

Dramatize answered 21/4, 2015 at 15:38 Comment(4)
Is this solution still applicable (iOS 11)? I followed the solution, but mapView(_:annotationView:didChange:fromOldState:) method never gets called.Nakamura
@Nakamura - This method is still called called (though the MKAnnotationViewDragState references are obviously now MKAnnotationView.DragState).Vernice
That having been said, I’ve been testing draggable annotations in various devices going back to iOS 10 and this method does just doesn’t appear to be needed. Perhaps only in older iOS versions?Vernice
@Vernice Yes, in my book the discussion of mapView(_:annotationView:didChange:fromOldState:) has been cut from the last several editions as being no longer needed.Dramatize

© 2022 - 2024 — McMap. All rights reserved.