matt matt - 1 year ago 52
iOS Question

iOS Swift MapKit making an annotation draggable by the user?

How do I make it possible, using iOS 8 and 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

, when my map view delegate creates the annotation view, like this:

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
var v : MKAnnotationView! = nil
let ident = "bike"
v = mapView.dequeueReusableAnnotationViewWithIdentifier(ident)
if v == nil {
v = MyAnnotationView(annotation:annotation, reuseIdentifier:ident)
v.annotation = annotation
v.draggable = 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?

Answer Source

It isn't enough to mark the annotation view as draggable. You must also implement mapView:annotationView:didChangeDragState: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!, didChangeDragState 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.)