Use two different UIViewAnimationCurves in the same animation
Asked Answered
C

3

5

I want to be able to use one UIViewAnimationCurve for rotations and another for changes in position. Is this possible?

For example (in pseudo code);

// Begin animations

// Set rotation animation curve to EaseInOut

// Set position animation curve to Linear

// Make some changes to position

// Make some change to the angle of rotation

// Commit the animations

EDIT: (CAAnimationGroup approach suggested below) - Have created 2 separate CABasicAnimations and a CAAnimationGroup however the animations are not starting. Any ideas?

CABasicAnimation *postionAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
postionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
postionAnimation.toValue = [NSValue valueWithCGPoint:[self transformPointToWorldSpaceFromViewSpace:self.spriteView.position]];
postionAnimation.delegate = self;

CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.z"];
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
rotationAnimation.toValue = [NSNumber numberWithFloat:self.spriteView.angle -= M_PI_2];
rotationAnimation.delegate = self;

CAAnimationGroup *animationsGroup = [CAAnimationGroup animation];
animationsGroup.duration = self.clockSpeed;
animationsGroup.animations = [NSArray arrayWithObjects:postionAnimation, rotationAnimation, nil];

// Perform the animation
[self.spriteView.layer addAnimation:animationsGroup forKey:nil];
Cloud answered 12/7, 2012 at 9:38 Comment(0)
C
3

Your best bet is to use multiple calls to animateWithDuration:delay:options:animations:completion:. Use a different animation curve in each call, and they will run in parallel. Or, with different delay values, you can make them run in sequence.

The code might look like this:

[UIView animateWithDuration: .5 
  delay: 0
  options: UIViewAnimationOptionCurveEaseInOut 
  animations: ^{
    view1.center = CGPointMake(x, y);
  }
  completion:  ^{
    //code that runs when this animation finishes
  }
];

[UIView animateWithDuration: .5 
  delay: .5
  options: UIViewAnimationOptionCurveLinear
  animations: ^{
    view2.center = CGPointMake(x2, y2);
  }
  completion:  ^{
    //code that runs when this animation finishes
  }
];

If you use CAAnimationGroups, there are several problems.

First, the animation group determines the animation curve for the entire group. I don't think you can specify different curves for each sub animation (although I confess I haven't tried it.)

Secondly, if you add animations to a group, the delegates to the individual animations don't get called. Only the animation group's delegate methods get called.

Cathepsin answered 14/7, 2012 at 1:41 Comment(2)
This is great advice, thanks Duncan. Will give it a go tomorrow. DaveCloud
Hi Duncan, done this and works a treat! The only question I have is, is it ok to call my method [self transformPointToViewSpaceFromWorldSpace:self.spriteView.position] within the block? It works and instruments doesn't show any leaks, however I vaguely remember something about using self within blocks. Thanks again, Dave.Cloud
S
4

Try by creating two different animations. With method of UIView you can't set different animationsCurves for different properties of your animation. Or you can have fun with CAAnimations and create a CAAnimationGroup in which you set your two CABasicAnimation

Starch answered 12/7, 2012 at 9:41 Comment(1)
Thanks iSofTom, have tried this approach (see edit in question) but according to the delegate methods my animations aren't starting. Any ideas?Cloud
C
3

Your best bet is to use multiple calls to animateWithDuration:delay:options:animations:completion:. Use a different animation curve in each call, and they will run in parallel. Or, with different delay values, you can make them run in sequence.

The code might look like this:

[UIView animateWithDuration: .5 
  delay: 0
  options: UIViewAnimationOptionCurveEaseInOut 
  animations: ^{
    view1.center = CGPointMake(x, y);
  }
  completion:  ^{
    //code that runs when this animation finishes
  }
];

[UIView animateWithDuration: .5 
  delay: .5
  options: UIViewAnimationOptionCurveLinear
  animations: ^{
    view2.center = CGPointMake(x2, y2);
  }
  completion:  ^{
    //code that runs when this animation finishes
  }
];

If you use CAAnimationGroups, there are several problems.

First, the animation group determines the animation curve for the entire group. I don't think you can specify different curves for each sub animation (although I confess I haven't tried it.)

Secondly, if you add animations to a group, the delegates to the individual animations don't get called. Only the animation group's delegate methods get called.

Cathepsin answered 14/7, 2012 at 1:41 Comment(2)
This is great advice, thanks Duncan. Will give it a go tomorrow. DaveCloud
Hi Duncan, done this and works a treat! The only question I have is, is it ok to call my method [self transformPointToViewSpaceFromWorldSpace:self.spriteView.position] within the block? It works and instruments doesn't show any leaks, however I vaguely remember something about using self within blocks. Thanks again, Dave.Cloud
C
0

Ok, finally solved it. Thanks for the direction iSofTom (have up voted your answer). I had set the delegates of the individual animations but not the group.

CABasicAnimation *postionAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
postionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
postionAnimation.fromValue = [NSValue valueWithCGPoint:self.spriteView.center];
postionAnimation.toValue = [NSValue valueWithCGPoint:[self transformPointToViewSpaceFromWorldSpace:self.spriteView.position]];

CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
rotationAnimation.fromValue = [NSNumber numberWithFloat:self.spriteView.angle];
rotationAnimation.toValue = [NSNumber numberWithFloat:self.spriteView.rotation];

CAAnimationGroup *animationsGroup = [CAAnimationGroup animation];
animationsGroup.duration = self.clockSpeed;
animationsGroup.animations = [NSArray arrayWithObjects:postionAnimation, rotationAnimation, nil];
animationsGroup.delegate = self;
// Perform the animation
[self.spriteView.layer addAnimation:animationsGroup forKey:nil];

and

- (void)animationDidStart:(CAAnimation *)theAnimation {
radiansToDegrees(self.spriteView.rotation));
    self.spriteView.angle = self.spriteView.rotation;

NSStringFromCGPoint(self.spriteView.position));
    self.spriteView.center = [self transformPointToViewSpaceFromWorldSpace:self.spriteView.position];
}
Cloud answered 12/7, 2012 at 21:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.