Search code examples
iphoneiosdraggablemkannotation

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:

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

Solution

  • 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);
        }
    }