Kimmo
Kimmo

Reputation: 1956

How to animate map annotation movement correctly?

I'm displaying real time locations of city's buses on MKMapView. My app polls locations with certain interval and updates them on map. I'm trying to animate movement of the map annotations.

I have successfully animated movement with the following code found from this stackoverflow answer:

- (void)moveBusAnnotation:(TKLBus*)bus coordinate:(CLLocationCoordinate2D)coordinate {
    [UIView animateWithDuration:0.5f
    animations:^(void){
        bus.annotation.coordinate = coordinate;
    }];
}

Problem is that when user pans or zooms the map while animation is playing, the motion path of the annotation looks weird and buggy. Here's a demonstration:

map annotation animation

Notice how the map annotation follows a strange curve instead of straight line. Bus movement is simulated so ignore its strange position on map.

How can I make the animation look more natural or stop animations while map is panned/zoomed?

Edit: The animation seems to do the right thing. It looks weird just because the map annotation's next coordinate is moving while the animation plays. I think the solution would be to prevent animations while user is touching the screen.

Upvotes: 3

Views: 1105

Answers (1)

freshking
freshking

Reputation: 1864

Try this:

Set up a bool that will indicate wether the map is being used by the user:

@property (nonatomic, assign) BOOL userIsInteracting;

Then check the users touches in the map:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];

    for (UITouch * touch in touches) 
    {
        CGPoint loc = [touch locationInView:_mapView];
        if ([_mapView pointInside:loc withEvent:event]) 
        {
            _userIsInteracting = YES;
            break;
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    for (UITouch * touch in touches) 
    {
        CGPoint loc = [touch locationInView:_mapView];
        if ([_mapView pointInside:loc withEvent:event]) 
        {
            _userIsInteracting = NO;
            break;
        }
    }
}

Now you know when to animate the location in the map:

- (void)moveBusAnnotation:(TKLBus*)bus coordinate:(CLLocationCoordinate2D)coordinate 
{
    if (_userIsInteracting) return;

    [UIView animateWithDuration:0.5f
                     animations:^(void){
                     bus.annotation.coordinate = coordinate;
                     }];
}

Upvotes: 1

Related Questions