6

How do you implement kCATransitionPush using CAAnimation subclasses in iOS?

CAAnimation *animation;
// How do you create an animation that does the same than:
// CATransition *animation = [CATransition animation];
// [animation setType:kCATransitionPush];        
[self.view.layer addAnimation:animation forKey:nil];

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];        
[self.view addSubview:change];
[UIView commitAnimations];

I'm aware that UIView animations can also be used, but it would help me to understand Core Animation better if I could implement a kCATransitionPush transition from the ground-up.

Community
  • 1
  • 1
hpique
  • 119,096
  • 131
  • 338
  • 476

2 Answers2

11

In order to execute the animations simultaneously over the two layers, you must add the adequate CAAnimationGroup to each layer.

[nextView.layer addAnimation:nextViewAnimation forKey:nil];
[currentView.layer addAnimation:currentViewAnimation forKey:nil];

nextViewAnimation would be:

CAAnimationGroup *nextViewAnimation = [CAAnimationGroup animation];
NSMutableArray *nextAnimations = [NSMutableArray array];

[nextAnimations addObject:[self opacityAnimation:YES]];  // fade in

CGPoint fromPoint = CGPointMake(forward ? nextView.center.x + nextView.frame.size.width : nextView.center.x - nextView.frame.size.width, nextView.center.y);
[nextAnimations addObject:[self positionAnimationFromPoint:fromPoint toPoint:nextView.center]];  // traslation in

nextViewAnimation.animations = nextAnimations;

and currentViewAnimation:

CAAnimationGroup *currentViewAnimation = [CAAnimationGroup animation];
NSMutableArray *currentAnimations = [NSMutableArray array];
[currentSceneAnimations addObject:[self opacityAnimation:NO]]; // fade out

CGPoint toPoint = CGPointMake(forward ? currentView.center.x - currentView.frame.size.width : currentView.center.x + currentView.frame.size.width, currentView.center.y);
    [currentAnimations addObject:[self positionAnimationFromPoint:currentView.center toPoint:toPoint]];  // traslation out

currentViewAnimation.animations = currentAnimations;

These methods create the basic animations:

- (CABasicAnimation *)opacityAnimation:(BOOL)fadeIn {
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
a.fromValue = [NSNumber numberWithFloat:fadeIn ? 0.0 : 1.0];
a.toValue = [NSNumber numberWithFloat:fadeIn ? 1.0 : 0.0];
return a;
}

- (CABasicAnimation *)positionAnimationFromPoint:(CGPoint)fromPoint toPoint:(CGPoint)toPoint {
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"position"];
a.fromValue = [NSValue valueWithCGPoint:fromPoint];
a.toValue = [NSValue valueWithCGPoint:toPoint];
return a;
}

With the boolean forward you can simulate the transition "from left" or "from right".

LoDani
  • 325
  • 2
  • 8
4

The default kCATransitionPush does indeed include a fade. To replicate the transition using your own CABasicAnimation you'll first need to understand how the push animation works. I do this without testing so this might be off, but if I remember correctly the animation where sublayer B replaces sublayer A works like this:

  • Layer A moves from original position to the right
  • Layer B moves from right to original position of A
  • Lirst half of the animation layer B animates its opacity from 0 to 1
  • Second half of the animation layer A animates its opacity from 1 to 0 (of course you can replace right with any direction here).

CABasicAnimation only supports animating one property, so you'll have to create a CAAnimationGroup which controls the 4 different animations.

Create the animations for position and opacity like this:

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];
anim.fromValue = [NSValue valueWithCGPoint:startPoint];
anim.toValue = [NSValue valueWithCGPoint:endPoint];

CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"opacity"];
anim.fromValue = [NSNumber numberWithFloat:0.0];
anim.toValue = [NSNumber numberWithFloat:1.0];
Alexsander Akers
  • 15,967
  • 12
  • 58
  • 83
Joris Kluivers
  • 11,894
  • 2
  • 48
  • 47
  • Thanks Joris. It's not view A the replaces view B. It's the original state of the view that is replaced by the new state. – hpique Apr 13 '11 at 07:04
  • Sorry, somehow I'm using the word view, where I should have used CALayer. A transition indeed works on the View contents: I don't know the implementation by Apple, might as well be OpenGL supporting the CALayer content animation. Best way to do it yourself would be they way described above applied to sublayers. – Joris Kluivers Apr 13 '11 at 07:51
  • How do you differentiate between sublayer A and sublayer B? CATransition appears to do this automagically. – hpique Oct 17 '11 at 18:34