I have path stored in an array of CGPoints which I'd like to move an image along. Here's the general code I have so far:
-(void)movePic:(id)sender{
for(int i = 0; i < self.array.count; i++){
CGPoint location = [[self.array objectAtIndex:i] CGPointValue];
[UIView animateWithDuration:0.1 animations:^{
self.imageView.center = location;
} completion:^(BOOL finished){
}];
}
}
The problem is the for loop runs extremely fast, so you only see the animation on the last points. I'm unsure of how to better design this. Ideally, what could I do to make sure one animation finishes before the other begins? Should I not use a for loop? Thanks
Your code assumes that UIView animations run synchronously in the main thread, which they do not.
You seem to have two options
CAKeyframeAnimation for animating a CALayer along any amount of sample points (interpolated between them)UIView animation for animating a UIView along a series of sample points (interpolated between them)The former would be much more efficient - still I thought I oould show you both options.
- (void)movePic:(id)sender
{
//create a mutable core-graphics path
CGMutablePathRef path = CGPathCreateMutable();
for(int i = 0; i < self.array.count; i++)
{
CGPoint location = [[self.array objectAtIndex:index] CGPointValue];
CGPathAddLineToPoint(path, nil, location.x, location.y);
}
//create a new keyframe animation
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//add our path to it
pathAnimation.path = path;
//be nice to the system
CGPathRelease(path);
//setup some more animation parameters
pathAnimation.duration = 0.1 * self.array.count;
//add the animation to our imageView's layer (which will start the animation)
[self.imageView.layer addAnimation:pathAnimation forKey:@"pathAnimation"];
}
- (void)movePicToPointAtIndex:(unsigned int)index
{
//safeguard check...
if ([self.array count] <= index)
return;
//get the next location
CGPoint location = [[self.array objectAtIndex:index] CGPointValue];
//animate the imageView center towards that location
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionAllowUserInteraction
animations:^{
self.imageView.center = location;
} completion:^(BOOL finished){
//we are done with that animation, now go to the next one...
[self movePicToPointAtIndex:index+1];
}];
}
- (void)movePic:(id)sender
{
[self movePicToPointAtIndex:0];
}
Ok, the thing you have to do is set the array of points as a property of the class, something like animationPath. Ok, so now you would have to pay attention to the delegate methods of the UIView animation delegate methods (it's not actually a different class, it's just a delegate of the class' methods).
Set a method to call on setAnimationDidStopSelector:selector every time the animation stops, so here you would have something like this:
//Inside the callback for setAnimationDidStopSelector
if ([animationPath count] != 0){
//Go to next point
CGPoint location = [[self.array objectAtIndex:0] CGPointValue];
[UIView animateWithDuration:0.1 animations:^{
self.imageView.center = location;
} completion:^(BOOL finished){
}];
}
else{
NSLog(@"Nowhere else to go, animation finished :D");
}
So just be sure to fire your animation with the first point.
As far as I remember UIViews animations manage things in other threads so that's probably why the for statement is not working.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With