动画控制属性
duration
duration:对将要进行的动画的一次迭代指定了时间;
repeatCount
repeatCount:代表动画重复的迭代次数。如果duration是2,repeatCount设为3.5(三个半迭代),那么完整的动画时长将是7秒;
duration和repeatCount默认都是0。但这不意味着动画时长为0秒,或者0次,这里的0仅仅代表了“默认”,也就是0.25秒和1次
autoreverses
自动(返回)动画
repeatDuration
创建重复动画的另一种方式是使用repeatDuration属性,它让动画重复一个指定的时间,而不是指定次数。你甚至设置一个叫做 autoreverses的属性(BOOL类型)在每次间隔交替循环过程中自动回放。这对于播放一段连续非循环的动画很有用,例如打开一扇门,然后关上它 (图9.2)。
对门进行摆动的代码见清单9.2。我们用了autoreverses来使门在打开后自动关闭,在这里我们把repeatDuration设置为 INFINITY,于是动画无限循环播放,设置repeatCount为INFINITY也有同样的效果。注意repeatCount和 repeatDuration可能会相互冲突,所以你只要对其中一个指定非零值。对两个属性都设置非0值的行为没有被定义。
清单9.2 使用autoreverses属性实现门的摇摆
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
CALayer *doorLayer = [CALayer layer];
doorLayer.frame = CGRectMake(0, 0, 128, 256);
doorLayer.position = self.view.center;
doorLayer.anchorPoint = CGPointMake(0, 0.5);
doorLayer.contents = (__bridge id)[UIImage imageNamed: @"bjl_list_02"].CGImage;
[self.view.layer addSublayer:doorLayer];
//apply perspective transform
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 500.0;
self.view.layer.sublayerTransform = perspective;
//apply swinging animation
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = @"transform.rotation.y";
animation.toValue = @(-M_PI_2);
animation.duration = 1;
//animation.repeatDuration = INFINITY;
animation.autoreverses = YES;
[doorLayer addAnimation:animation forKey:nil];
}
@end
beginTime
beginTime:指定了动画开始之前的的延迟时间。这里的延迟从动画添加到可见图层的那一刻开始测量,默认是0(就是说动画会立刻执行),然而在层级关系中,beginTime指定了父图层开始动画(或 者组合关系中的父动画)和对象将要开始自己动画之间的偏移
speed
speed:是一个时间的倍数,默认1.0,减少它会减慢图层/动画的时间,增加它会加快速度。如果2.0的速度,那么对于一个duration为1的动画,实际上在0.5秒的时候就已经完成了;
timeOffset
timeOffset:和beginTime类似,但是和增加beginTime导致的延迟动画不同,增加timeOffset只是让动画快进到某一点,例如,对于一个持续1秒的动画来说,设置timeOffset为0.5意味着动画将从一半的地方开始。和beginTime不同的是,timeOffset并不受speed的影响。
避免在动画结束的时候急速返回提供另一种方案:
@interface ViewController ()<CAMediaTiming>
{
CALayer *doorLayer;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
doorLayer = [CALayer layer];
doorLayer.frame = CGRectMake(0, 0, 128, 256);
doorLayer.position = self.view.center;
doorLayer.anchorPoint = CGPointMake(0, 0.5);
doorLayer.contents = (__bridge id)[UIImage imageNamed: @"bjl_list_02"].CGImage;
[self.view.layer addSublayer:doorLayer];
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0 / 500.0;
self.view.layer.sublayerTransform = perspective;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//add the door
//apply perspective transform
//apply swinging animation
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = @"transform.rotation.y";
animation.byValue = @(-M_PI_4);
animation.duration = 1;
animation.fillMode=kCAFillModeBoth;
animation.removedOnCompletion=NO;
//animation.repeatDuration = INFINITY;
[doorLayer addAnimation:animation forKey:nil];
}
fillMode
四种常量:
kCAFillModeForwards
kCAFillModeBackwards
kCAFillModeBoth
kCAFillModeRemoved
默认是kCAFillModeRemoved.但是记住了,当用它来解决这个问题的时候,需要把removeOnCompletion设置为NO,另外需要给动画添加一个非空的键,于是可以在不需要动画的时候把它从图层上移除。
层级关系时间
对CALayer或者CAGroupAnimation调整duration和repeatCount/repeatDuration属性并不会影响到子 动画。但是beginTime,timeOffset和speed属性将会影响到子动画。然而在层级关系中,beginTime指定了父图层开始动画(或 者组合关系中的父动画)和对象将要开始自己动画之间的偏移。类似的,调整CALayer和CAGroupAnimation的speed属性将会对动画以 及子动画速度应用一个缩放的因子。