Drag an annotation pin on a mapview

The annotation pin is draggable but I couldn’t drop it to the destination location. The problem is how could I get the destination location’s coordinate where i drop the annotation pin? Any method exist?

Edit 1:

  • How can I create a UIColor from a hex string?
  • How to animate the CABasicAnimation in background after the home button is pressed?
  • How to detect IOS 7 and IOS 8 and widescreen iPhone sizes to make my app universal?
  • How can I programmatically detect EDGE network or bad network in iPhone?
  • iOS - How can I schedule something once a day?
  • Parse Swift IOS - PFCloud callFunctionInBackground Selector not invoked
  • The center of the annotation pin seems never changed where ever I drop the pin.

    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState 
    fromOldState:(MKAnnotationViewDragState)oldState 
    {
    if (newState == MKAnnotationViewDragStateEnding)
    {
        NSLog(@"x is %f", annotationView.center.x);
        NSLog(@"y is %f", annotationView.center.y);
    
        CGPoint dropPoint = CGPointMake(annotationView.center.x, annotationView.center.y);
        CLLocationCoordinate2D newCoordinate = [self.mapView convertPoint:dropPoint toCoordinateFromView:annotationView.superview];
        [annotationView.annotation setCoordinate:newCoordinate];
    
    }
    }
    

    Edit 2:

    Annotation.h

    @property (nonatomic,readwrite,assign) CLLocationCoordinate2D coordinate;
    

    Annotation.m

    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
    coordinate = newCoordinate; 
    }
    

    Edit 3:
    where ever I drag the pin, the NSLog out put of the droppedAt is always the same.

    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState 
    fromOldState:(MKAnnotationViewDragState)oldState 
    {
    if (newState == MKAnnotationViewDragStateEnding)
    {
        CLLocationCoordinate2D droppedAt = annotationView.annotation.coordinate;
        NSLog(@"Pin dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
    }
    }
    

    Edit 4:

    Annotaion.m
    @dynamic startAddr;

    - (CLLocationCoordinate2D)coordinate
    {
    coordinate.latitude = [self.startAddr.latitude doubleValue];
    coordinate.longitude = [self.startAddr.longitude doubleValue];    
    return coordinate;
    }
    
    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
    //I need to update the self.startAddr.latitude and longitude here. Problem solved.
    self.startAddr.latitude = [NSNumber numberWithDouble:newCoordinate.latitude];
    self.startAddr.longitude = [NSNumber numberWithDouble:newCoordinate.longitude];
    
    coordinate = newCoordinate; 
    }
    

    6 Solutions Collect From Internet About “Drag an annotation pin on a mapview”

    First you have to create a custom annotation like this:

    MyAnnotation.h

    #import <MapKit/MapKit.h>
    
    @interface MyAnnotation : NSObject <MKAnnotation>{
    
        CLLocationCoordinate2D coordinate;
    
    }
    - (id)initWithCoordinate:(CLLocationCoordinate2D)coord;
    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate;
    @end
    

    MyAnnotation.m

    #import "MyAnnotation.h"
    
    @implementation MyAnnotation
    @synthesize coordinate;
    
    - (NSString *)subtitle{
        return nil;
    }
    
    - (NSString *)title{
        return nil;
    }
    
    -(id)initWithCoordinate:(CLLocationCoordinate2D)coord {
        coordinate=coord;
        return self;
    }
    
    -(CLLocationCoordinate2D)coord
    {
        return coordinate;
    }
    
    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
        coordinate = newCoordinate; 
    }
    
    @end
    

    After that, you just have to use your annotation like this:

    // Assuming you have imported MyAnnotation.h and you have a self.map property pointing to a MKMapView
    MyAnnotation *myPin = [[MyAnnotation alloc] initWithCoordinate:self.map.centerCoordinate]; // Or whatever coordinates...
    [self.map addAnnotation:myPin];
    

    Also, you have to return a view for your annotation. You can do so like this:

    - (MKAnnotationView *) mapView: (MKMapView *) mapView viewForAnnotation: (id<MKAnnotation>) annotation {
        MKPinAnnotationView *pin = (MKPinAnnotationView *) [self.map dequeueReusableAnnotationViewWithIdentifier: @"myPin"];
        if (pin == nil) {
            pin = [[[MKPinAnnotationView alloc] initWithAnnotation: annotation reuseIdentifier: @"myPin"] autorelease]; // If you use ARC, take out 'autorelease'
        } else {
            pin.annotation = annotation;
        }
        pin.animatesDrop = YES;
        pin.draggable = YES;
    
        return pin;
    }
    

    Then, once you have adopted the MKMapViewDelegate protocol in your controller, you grab the coordinates of a pin after dragging it like this:

    - (void)mapView:(MKMapView *)mapView 
     annotationView:(MKAnnotationView *)annotationView 
    didChangeDragState:(MKAnnotationViewDragState)newState 
       fromOldState:(MKAnnotationViewDragState)oldState 
    {
        if (newState == MKAnnotationViewDragStateEnding)
        {
            CLLocationCoordinate2D droppedAt = annotationView.annotation.coordinate;
            NSLog(@"Pin dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
        }
    }
    

    Out of the blue, implement the setCoordinates method of your annotation and make a callBAck when your annotation coordinates have changed

    edit : beware of the dragState property of your annotation while its moving.

    Don’t you wan’t to do this :

    Setting the annotation delegate,
    then

    - (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
       coordinate = newCoordinate; 
       if (self.delegate respondsToSelector:@selector(mapAnnotationCoordinateHaveChanged))
        [self.delegate performSelector(@selector(mapAnnotationCoordinateHaveChanged))];
    }
    

    In your delegate :

    - (void) mapAnnotationCoordinateHaveChanged{
     //some coordinates update code
    }
    
    - (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
    {
        MKAnnotationView *a = [ [ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier:@"currentloc"];
        //  a.title = @"test";
        if ( a == nil )
            a = [ [ MKAnnotationView alloc ] initWithAnnotation:annotation reuseIdentifier: @"currentloc" ];
    
        NSLog(@"%f",a.annotation.coordinate.latitude);
        NSLog(@"%f",a.annotation.coordinate.longitude);
    
        CLLocation* currentLocationMap = [[[CLLocation alloc] initWithLatitude:a.annotation.coordinate.latitude longitude:a.annotation.coordinate.longitude] autorelease];
        [self coordinatesToDMS:currentLocationMap];
    
    
        MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:a reuseIdentifier:@"currentloc"];
        if(a.annotation.coordinate.longitude == mapView.userLocation.coordinate.longitude ||  a.annotation.coordinate.latitude == mapView.userLocation.coordinate.latitude  )
        {
            if ([annotation isKindOfClass:MKUserLocation.class])
            {
                //user location view is being requested,
                //return nil so it uses the default which is a blue dot...
                return nil;
            }       
            //a.image = [UIImage imageNamed:@"userlocation.png"];
            //a.pinColor=[UIColor redColor];
        }
        else 
        {
    
            // annView.image =[UIImage imageNamed:@"map-pin.png"];
            //PinFirst=FALSE;
            //annView.pinColor = [UIColor redColor];
            // annView.annotation=annotation;
        }
    
        annView.animatesDrop = YES;
        annView.draggable = YES;
    
        annView.canShowCallout = YES;
    
        return annView;
    }
    
    - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
    {
        NSLog(@"map Drag");
    }
    
    - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState
    fromOldState:(MKAnnotationViewDragState)oldState;
    {
        NSLog(@"pin Drag");
    
        if (newState == MKAnnotationViewDragStateEnding)
        {
            CLLocationCoordinate2D droppedAt = view.annotation.coordinate;
            NSLog(@"Pin dropped at %f,%f", droppedAt.latitude, droppedAt.longitude);
    
            CLLocation* draglocation = [[[CLLocation alloc] initWithLatitude:droppedAt.latitude longitude:droppedAt.longitude] autorelease];
    
    
    
        }
    }
    

    Example for Swift 2.2, Xcode 7.3.1:

    • Create custom class adopting MKAnnotation protocol

      (note: Swift doesn’t have automatic notification for KVO-compliant properties, so I have added my own – this is not required):

      import MapKit
      
      class MyAnnotation: NSObject, MKAnnotation {
      
          // MARK: - Required KVO-compliant Property
          var coordinate: CLLocationCoordinate2D {
              willSet(newCoordinate) {
                  let notification = NSNotification(name: "VTAnnotationWillSet", object: nil)
                  NSNotificationCenter.defaultCenter().postNotification(notification)
              }
      
              didSet {
                  let notification = NSNotification(name: "VTAnnotationDidSet", object: nil)
                  NSNotificationCenter.defaultCenter().postNotification(notification)
              }
          }
      
      
          // MARK: - Required Initializer
          init(coordinate: CLLocationCoordinate2D) {
              self.coordinate = coordinate
          }
      }
      
    • Declare pin view as draggable:

      // MARK: - MKMapViewDelegate Actions
      func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
      
          let pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: pinViewReuseIdentifier)
          pinView.draggable = true
      
          return pinView
      }
      

    Now, when the pin is dragged, it invokes the delegate method:

    func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView)
    

    Here, you can retrieve the new end coordinates.


    Alternatively, you could create a userInfo dictionary for the custom annotation’s coordinate property’s notifications. Observers could then retrieve the values upon receipt of the notification.

    In Swift my problem was that the coordinate attribute was a letin my subclass and not a var as it is in the MKAnnotation.

    class MyAnnotation  : NSObject, MKAnnotation {
    
        let title       : String?
        let subtitle    : String?
        var coordinate  : CLLocationCoordinate2D
    
        init(title: String, subtitle: String, coordinate: CLLocationCoordinate2D) {
            self.title = title
            self.subtitle = subtitle
            self.coordinate = coordinate
            super.init()
        }
    }