Implementing a CATransition push with CAAnimation
Asked Answered
S

2

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.

Stokehole answered 9/4, 2011 at 11:25 Comment(0)
F
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".

Fastening answered 24/10, 2011 at 15:27 Comment(0)
E
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];
Erastianism answered 12/4, 2011 at 22:52 Comment(3)
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.Stokehole
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.Erastianism
How do you differentiate between sublayer A and sublayer B? CATransition appears to do this automagically.Stokehole

© 2022 - 2024 — McMap. All rights reserved.