Is it possible to move the coordinate of a MKAnnotation without adding and removing the annotation from the map?
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
}
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];
}];
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.
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"];
}
Subclass MKPointAnnotation and it has the capability to update the annotation view on the map to the new coordinate automatically.
dynamic var coordinate
or else KVO will not be automatic –
Urquhart Don't know whether it's more generally possible, but it is if you have your own custom MKAnnotationView.
I was able to adapt the approach documented at http://spitzkoff.com/craig/?p=108 by Craig Spitzkoff:
- Give your custom MKAnnotationView a reference to your MKAnnotation object
- Add an updateCoordinates method to the MKAnnotation object and call it when you want to change location of the annotation
- Call regionChanged on the custom MKAnnotationView to let it know when to reposition itself (e.g. when MKAnnotation has updated coordinates)
- In drawRect on the internal view object owned by your custom MKAnnotationView you can reposition using the coordinates of the MKAnnotation (you're holding a reference to it).
You could likely simplify this approach further - you may not require an internal view object in all circumstances.
If you keep a reference to your annotation, make a change to the coordinate property, then add the annotation to the map again, the location of the annotation view will update. You do not need to remove the annotation (which will cause the annotation view to momentarily disappear). This will not give you a nice transition for when the annotation coordinate is updated however. It also does not result in a memory leak nor are there a multiple of the same annotation added to the map (if you look at the number of annotations on the mapview, it remains constant when you re-add the annotation).
mapView.addAnnotation(myAnnotation)
doesn't move the annotation, but if I print the coordinates, they effectively change. I wonder why. –
Jezebel Most answers are based on fact that your Annotation has been made via MKPlacemark extending. But what about any other object (i.e. custom image for marker) which only implements MKAnnotation protocol? It wouldn't have the setCoordinate method. So here is the answer based on code, provided by 100grams
MKAnnotationView *av = [self.mapView viewForAnnotation:user];
//user is an object which implements <MKAnnotation>
// You will probably get your MKAnnotationView in your own way
if (av){
// here user returns CLLocationCoordinate2D coordinate
MKMapPoint mapPoint = MKMapPointForCoordinate([user getLastLocation]);
// converting mapPoint to CGPoint
CGPoint newPos;
CGFloat zoomFactor = self.mapView.visibleMapRect.size.width / self.mapView.bounds.size.width;
newPos.x = mapPoint.x/zoomFactor;
newPos.y = mapPoint.y/zoomFactor;
// animation for annotation's move
static NSString *POSITION_KEY=@"positionAnimation";
static NSString *PATH_ANIMATION_KEY=@"position";
if (MKMapRectContainsPoint(self.mapView.visibleMapRect, mapPoint)) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:PATH_ANIMATION_KEY];
animation.fromValue = [NSValue valueWithCGPoint:av.center];
animation.toValue = [NSValue valueWithCGPoint:newPos];
animation.duration = 0.3;
animation.delegate = av;
animation.fillMode = kCAFillModeForwards;
[av.layer addAnimation:animation forKey:POSITION_KEY];
}
// moving view
av.center = newPos;
so You basically need to get the corresponding MKAnnotationView which could be also achieved by iteration via all of annotations and it's new location. I made an array holder for all of it (NSMutableArray *mapAnnotaions) so now I could iterate just like:
for (id annotation in mapAnnotaions) {call refresh method here for id}
After you update the coordinates or some other properties of the annotation, just call following MKMapViewDelegate method to redraw your annotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation;
e.g.:
myAnnotation.coordinate = CLLocationCoordinate2DMake([newLat doubleValue], [newLon doubleValue]);
[self mapView:self.mapView viewForAnnotation:myAnnotation];
Take a look at my MapKitDragAndDrop sample, it allows you to update MKAnnotation and move MKAnnotationView on both iPhone OS 3 and iOS 4 (will use built-in dragging support).
It doesn't seem possible to change the coordinate of a MKAnnotation object and then inform the MKMapView of the change.
However, removing the previous annotation from the map, changing the coordinate of your annotation object and adding it back to the map works well.
[theMapView removeAnnotation:myAnnotation];
[myAnnotation setLatitude:newLatitude];
[theMapView addAnnotation:myAnnotation];
Why don't you want to do it this way?
© 2022 - 2024 — McMap. All rights reserved.