How to move a MKAnnotation without adding/removing it from the map?

20,408

Solution 1

In Swift 4.0 and IOS 11.0, I just add dynamic attribute to the coordinate property of child class of MKAnnotation class and it works: All Annotations on MapView update their location if coordinate value of MKAnnotation objects are updated:

class CarAnnotation: NSObject, MKAnnotation {
    @objc dynamic var coordinate: CLLocationCoordinate2D
    //Add your custom code here
}

Solution 2

I found a pretty simple method. I wanted to update my player's position smoothly without removing and then re-adding the player annotation. This works well for pre-iOS4 apps, and what it does is both move the pin and center the map on the pin's new location:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[player setCoordinate:aLoc.coordinate];
[mapView setCenterCoordinate:aLoc.coordinate animated:NO];
[UIView commitAnimations];

Here's the same thing but using the recommended block feature for iOS4:

[UIView animateWithDuration:0.5 animations:^{
    [player setCoordinate:aLoc.coordinate];
    [mapView setCenterCoordinate:aLoc.coordinate animated:NO];
}];

Solution 3

It is indeed possible without removing and adding the annotation off-course.

You'll need to observe your MKAnnotation's coordinate and update the MKAnnotationView's position when it changes. Alternatively you can (and this is probably the more elegant way of doing it) derive your own MKAnnotation and MKAnnotationView and make them "movable".

See Moving-MKAnnotationView for a detailed example which also animates the position of the annotation.

Solution 4

Subclass MKPointAnnotation and it has the capability to update the annotation view on the map to the new coordinate automatically.

Solution 5

Just use KVO:

[annotation willChangeValueForKey:@"coordinate"];
[annotation didChangeValueForKey:@"coordinate"];

If your MKAnnotation has an setCoordinate method, just include these lines right there:

- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate {
    [self willChangeValueForKey:@"coordinate"];
    coordinate = newCoordinate;
    [self didChangeValueForKey:@"coordinate"];
}
Share:
20,408
DevDevDev
Author by

DevDevDev

Updated on March 15, 2020

Comments

  • DevDevDev
    DevDevDev about 4 years

    Is it possible to move the coordinate of a MKAnnotation without adding and removing the annotation from the map?

  • DevDevDev
    DevDevDev about 14 years
    Yeah that's the solution I came up with, seems weird to have drawRect determine it's own frame though.
  • Lee Armstrong
    Lee Armstrong about 14 years
    Are you able to provide a sample to this at all please?
  • spstanley
    spstanley almost 14 years
    Any method that's updating your pin's position. For me, I have another object sending my map view controller a new position, which I then use to update my player pin's position. But you could receive a new position from an external source, or by the user touching a button or using drag-and-drop, whatever.
  • Stan
    Stan almost 12 years
    dunno why, but this method makes MapView to redraw itself, so I personally didn't like it.
  • Pradeep Reddy Kypa
    Pradeep Reddy Kypa over 11 years
    :- I clearly understand what u have mentioned in the above code snippet. I have upvoted your answer. Can you please explain on how to stop the animation at particular map points for a certain 2 seconds and then start moving the object again?
  • Stan
    Stan over 11 years
    About pause: I can't provide you the code but I guess you could use [NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:] for pause between map points. That also will give user a chance to use GUI while animation is paused.
  • Pradeep Reddy Kypa
    Pradeep Reddy Kypa over 11 years
    :- The above approach might work if we need to stop the animation after certain time interval. But here we need to stop the animation based on the coordinate value and then resume after certain seconds. We can use the timer in this case to resume the animation but how to stop the animation based on the coordiinate value?
  • Stan
    Stan over 11 years
  • delany
    delany over 11 years
    This seems to work. I'm just moving the annotation, not resetting the center - but I don't get any MapView redraws. One issue I do get (which is also an issue with the other, more complex, solutions here) is that the annotation vanishes if you zoom during the animation phase. It reappears at the end of the animation, so it's not a huge deal.
  • jfisk
    jfisk over 11 years
    the OP is asking for this, and for many users its ncier to see a smooth transition
  • malhal
    malhal about 10 years
    It is possible, see my answer above.
  • malhal
    malhal about 10 years
    Or if you extend MKPointAnnotation then it already has a coordinate property that supports KVO and automatically moves on the map.
  • Afzaal Ahmad
    Afzaal Ahmad almost 7 years
    Thanks its work smoothly. just update coordinate of annotation.
  • Ric Santos
    Ric Santos over 6 years
    In Swift, be sure to use dynamic var coordinate or else KVO will not be automatic
  • Samah
    Samah almost 6 years
    Should be the accepted answer. I never knew about this! You just saved me a bunch of time. ;)
  • Lawris
    Lawris about 5 years
    This actually does not work, if I remove and add the annotation it works. But simply modifying the coordinates properties and using mapView.addAnnotation(myAnnotation) doesn't move the annotation, but if I print the coordinates, they effectively change. I wonder why.
  • Ivan Le Hjelmeland
    Ivan Le Hjelmeland almost 5 years
    This is golden <3