How to remove an annotation from a map view gently? - ios

I'm adding and removing annotations to a map view. When I remove one it disappears abruptly and looks a bit startling, I'd rather it faded away gracefully.
I tried removing it with UIView:animateWithDuration: but it wasn't an animatable attribute.
If there's no other easy solution I was thinking I could get the annotation view to fade its alpha and then remove its annotation from the map. However the problem with this is it doesn't seem like an annotation view has a reference to its map view? Adding one starts to get a bit messy.
Is there some easy quick solution to removing an annotation gracefully?

Using animateWithDuration should work fine. To fade the removal of an annotation, one can:
MKAnnotationView *view = [self.mapView viewForAnnotation:annotation];
if (view) {
[UIView animateWithDuration:0.5 delay:0.0 options:0 animations:^{
view.alpha = 0.0;
} completion:^(BOOL finished) {
[self.mapView removeAnnotation:annotation];
view.alpha = 1.0; // remember to set alpha back to 1.0 because annotation view can be reused later
}];
} else {
[self.mapView removeAnnotation:annotation];
}

I think your proposed solution is the correct one. Set up an animation to opacity = 0, then, upon completion, remove the annotation from the MKMapView. The code that starts the animation doesn't have to be in the view itself; a better location for the code may be the view controller. Consider using NSNotificationCenter to notify the view controller that an annotation is requesting fade-out-and-remove.

Related

UIView animateWithDuration how to Cancel by touch event(No interaction with MapView)

I have a problem with my function.
[UIView animateWithDuration:5 animations:^{
//set end coordinates for marker = MKAnnotationPoint
[self.followDriverMarker setCoordinate:CLLocationCoordinate2DMake(latitde, longitude)];
//set end coordinate for camera/map
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latitde, longitude) animated:NO];
}
completion:^(BOOL finished) {
if (finished) {
if (self.currentPosition < [self.followDriverList count] - 2) {
self.currentPosition++;
//start next one
[self runAnimation];
} else {
//animation is finished
//TODO
self.isAnimationRunning = NO;
}
}
}];
The function will look in a List if there are locations left. If so it will run again. That works. The only problem is. If the animation is running. There is no interaction possible with the mapView. The other problem is that i cannot find how to cancel,stop or remove my Animation.
If I put:
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latitde, longitude) animated:NO];
inside the the completionBlock, I have interaction with map. But I don't want to do that because I want to animate it the same time. Also here I can't find a way to cancel the animation.
Please don't say removeAllAnimation. This is not working.
I believe this answers your question.
Basically you commit a new animation on the same target with a short duration. By setting the setAnimationBeginsFromCurrentState flag you prevent weird jumps.

Changing MKMapView's height AND centerCoordinate with animation causes annotations to flicker

I have a legacy code to maintain where I have a UIView and inside that container I have an MKMapView. There are custom annotations on this mapView. If I tap on them, the mapContainer and the mapView resizes their height, also the centerCoordinate of the mapView is set to the coordinate of the selected annotation.
#property(nonatomic,weak) IBOutlet UIView *mapContainer;
#property(nonatomic,weak) MKMapView *mapView;
To makes things more complicated these 3 things should happen at the same time animating together. The animation itself is working neatly, so the calculation of the bounds, center, etc should be fine.
#weakify(self);
[UIView animateWithDuration:self.detailsPanelSlideAnimationDuration animations:^ {
#strongify(self);
self.mapContainer.bounds = self.mapContainerViewWithDetailsFrame;
CGPoint center = CGPointMake(CGRectGetWidth(self.mapContainerViewWithDetailsFrame) / 2.0f, CGRectGetHeight(self.mapContainerViewWithDetailsFrame) / 2.0f);
self.mapContainer.center = center;
self.mapView.bounds = self.mapViewWithDetailsFrame;
self.mapView.center = self.mapContainer.center;
[self.mapView setCenterCoordinate:self.selectedAnnotation.coordinate animated:NO];
// setting other frames/bounds/centers not related to the map or annotations
...
} completion:NULL];
The problem is that during this animation the custom annotation images are not on the correct position. They are going to another direction. They jump into the right place after the animation has completed but this causes an unpleasant experience.
I would remove them before the animation and put them back after but they should be visible during the animation too. What do you suggest I should do?
EDIT:
I thought that forcing the annotations to redraw more frequently during the animation would help this problem, but I had no luck.
(I created a nested animation with repetition. Inside the animation block I iterated through the mapView's annotations and called setNeedsLayout.)

Trouble Instantiating MKAnnotationPoint in my mapView while another UIContainerView is present

The basic scenario is under everything, I have a map view in my view controller.
Above that, I animate an "annotationCreateView" on top of it. This view is already instantiated and moves between isHidden = No to isHidden = Yes and animates on and off screen accordingly.
However, I'm having trouble adding an annotation to the user's current location at the end of animating the view onscreen.
For some reason, the view will animate all the way up, and then upon executing the code where I add the annotation view, the view will disappear.
If I check for the IsHidden, it says no, meaning that it should be present. However, if I try to reanimate it up, it will slide all the way up and disappear again.
This is my code:
createAnnotationViewPresent = true;
[_annotationCreateView setHidden:NO];
[UIView animateWithDuration:1.0f animations:^{
CGRect frame = self.view.frame;
frame.size.height = frame.size.height/2;
frame.origin.y = frame.origin.y + frame.size.height;
_annotationCreateView.frame = frame;
} completion:^(BOOL finished) {
MKPointAnnotation *point = [[MKPointAnnotation alloc]init];
point.coordinate = _mapView.userLocation.coordinate;
[_mapView addAnnotation:point];
self.point = point;
}];
Any suggestions appreciated, let me know if you need more code or information.
So the Problem I was facing was that Apple's auto layout constraints make it such that after the View reaches the end of the animation and then the pin for the map view is placed on, it reaches a conflict. It then decides to resolve this conflict by resetting my view to it's original position and made it seem like it was never moved in the first place. At least as far as I understand :P. The solution to my problem was to simply relieve the view controller's auto layout constraints and voila, problem solved.

Keeping track of MKAnnotationView objects

What I wish to do is to fade-in and fade-out some custom annotation views. In order to do this I need to have the pointers to those views. Have been thinking of collecting these pointers in mapView:viewForAnnotation. But I am not sure if this is the right way.
The reason is since annotation views are set up to be recycled, I worry that they can be detached from their annotations once they are moved out of the screen. So my thinking is, view pointers collected in mapView:viewForAnnotation, may not be reliable since we don't know if they are still on the screen or not.
Hope somebody can suggest a proper way to keep track of these view pointers. Or suggest some other standard or reliable way of fading in and out the annotation views.
Update :
Just found out that viewForAnnotation does work. And I don't really need to keep track of the annotations (at least in this case) if they are on screen or not.
Try this where you get to the zoom that you want to animate the annotationViews:
for (MyAnnotation *annotation in myMapView.annotations)
{
MKAnnotationView *annotationView = [myMapView viewForAnnotation:annotation];
//Do your animation to the annotationView
//Example for fadeOut - fadeIn
[UIView animateWithDuration:0.5 animations:^{
annotationView.alpha = 0.2;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.5 animations:^{
annotationView.alpha = 1;
}];
}];
}
If you have all kinds of annotationView types and you want to animate just part of them, then you will need to check the type before the animation.

ios MapKit MKOverlayView animation happening instantly

I am trying to animate the alpha value of a MapKit overlay view (specifically an MKCircleView) in iOS 5 using the following code:
-(void) animateCircle:(MKCircle*)circle onMap:(MKMapView*) mapView
{
MKCircleView * circleView = (MKCircleView*) [mapView viewForOverlay:circle];
UIViewAnimationOptions options = UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionTransitionNone;
[UIView animateWithDuration:5.0
delay:0.0
options:options
animations:^(void) { circleView.alpha = 0.9; }
completion:^(BOOL finished) {}
];
}
The alpha value of the overlay is changing as I want, but it is jumping there instantaneously rather than animating over the specified duration.
Can anyone suggest what might be wrong? Perhaps animation on overlay views os more complex with blocks than I had thought.
Core Animation has interesting behavior when concurrent animations effect the same view... If you try to animate a view before the view's last animation finished, it will assume you intended the subsequent animation to start from the desired end-state of the initial one. This can result in jumps of frames as well as jumps of alpha values.
In your case, this view is likely being animated by something else. Try locating and removing the other animation / or'ing in UIViewAnimationOptionBeginFromCurrentState to its options.

Resources