使用CAAnimation实现CATransition推送

6

在iOS中,如何使用CAAnimation子类实现kCATransitionPush

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];

我知道可以使用UIView动画,但如果我能从头开始实现kCATransitionPush转换就会更好地理解核心动画

2个回答

11
为了同时在两个图层上执行动画,你必须向每个图层添加适当的CAAnimationGroup。
[nextView.layer addAnimation:nextViewAnimation forKey:nil];
[currentView.layer addAnimation:currentViewAnimation forKey:nil];

nextViewAnimation的含义是:

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;

和 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;

这些方法创建基本动画:

- (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;
}

通过布尔型变量forward,你可以模拟从左侧或右侧的转换。


4
默认的kCATransitionPush过渡确实包含淡入淡出效果。要使用自己的CABasicAnimation复制此过渡效果,您首先需要了解推送动画的工作原理。我这样做并没有测试,所以可能有误,但如果我记得正确,替换子图层B的动画是这样工作的:
  • 图层A从原始位置移动到右侧
  • 图层B从右侧移动到A的原始位置
  • 动画的前半部分,图层B将其不透明度从0动画到1
  • 动画的后半部分,图层A将其不透明度从1动画到0(当然你可以在这里用任何方向替换 right)。
CABasicAnimation只支持动画一个属性,因此您需要创建CAAnimationGroup来控制4种不同的动画。
像这样创建位置和不透明度动画:
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];

谢谢Joris。替换视图B的不是视图A,而是被新状态所替换的原始状态。 - hpique
抱歉,我有些地方使用了“View”这个词,但我应该使用CALayer。转换确实作用于视图内容:我不知道苹果的具体实现方式,也可能是OpenGL支持CALayer内容动画。自己执行此操作的最佳方法是将上述方式应用于子层。 - Joris Kluivers
你如何区分子层A和子层B?CATransition似乎可以自动完成这个任务。 - hpique

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接