Core Animation
图中紫色虚线表示继承关系,红色虚线表示遵守协议,核心动画中所有类都遵守CAMediaTiming协议;
CAAnimation包括的子类:
1.CABasicAnimation:基本动画,通过设定起始点,终点,时间,动画会沿着你设定的点进行移动。
2.CAKeyframeAnimation:帧动画,通过设定起始点,中间关键点,终点,时间,动画会沿着你设定的轨迹进行移动。
3.CAAnimationGroup:组合动画,把layer所有动画都组合起来,可以同时执行。
4.CATransition:转场动画,页面之间跳转时使用。
CAAnimation
是所有动画类的父类,负责设置动画的时间和速度,是个抽象类,不能直接使用。
基本属性:
- duration:动画持续的时间,默认是0;
- repeatCount:动画执行的次数,无线循环可以写HUGE_VALF或者MAXFLOAT,默认是0;
- repeatDuration:动画重复的时间,默认是0;
- beginTime:动画延迟执行时间,如果想要延迟2秒,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()是图层当前的时间,默认是0;
- autoreverses:动画是否返回,默认是NO不返回;
- speed:动画执行的速度,默认是1,如果设置为2,动画执行的时间duration减半;
- timeOffset:设置一个时间偏移量,根据父类的动画时间来确定时间;
- removedOnCompletion:默认为YES,动画执行完毕后会从图层中移除,图形会恢复到动画执行前的状态。如果想让图形保持显示在动画执行后的状态,那就设置为NO,不过还要设置fillMode为KCAFillModeForwards;
- fillMode:动画开始前和动画结束后的行为;
- timingFunction:速度控制函数,控制动画运动的节奏;
- delegate:动画代理;
fillMode属性:
想要fillMode有效,最好设置removedOnCompletion为NO;
- kCAFillModeRemoved:这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态;
- kCAFillModeForwards:当动画结束后,layer会一直保持着动画最后的状态;
- kCAFillModeBackwards:在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始;
- kCAFillModeBoth:这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态;
CAMediaTimingFunction速度控制函数:
- kCAMediaTimingFunctionLinear:线性,匀速,一个相对静态的感觉;
- kCAMediaTimingFunctionEaseIn:渐进,动画缓慢进入,然后加速离开;
- kCAMediaTimingFunctionEaseOut:渐出,动画全速进入,然后缓慢到达目的地;
- kCAMediaTimingFunctionEaseInEaseOut:渐进渐出,动画缓慢的进入,中间加速,然后减速的到达目的地;
- kCAMediaTimingFunctionDefault:默认状态;
CAPropertyAnimation
是CAAnimation的子类,也是个抽象类,要想创建动画,应使用它的子类CABasicAnimation和CAKeyframeAnimation。
基本属性:
- keyPath:设置动画的类型,想要实现什么样的动画效果。
- transform.scale.x:x轴方向伸缩;
- transform.scale.y:y轴方向伸缩;
- transform.scale.z:z轴方向伸缩;
- transform.scale:x,y,z轴方向都伸缩;
- transform.rotation.x:沿x轴方向旋转;
- transform.rotation.y:沿y轴方向旋转;
- transform.rotation.z:沿z轴方向旋转;
- transform.rotation:沿z轴方向旋转;
- position.x:沿x轴方向移动;
- position.y:沿y轴方向移动;
- position.z:沿z轴方向移动;
- position:按x,y坐标点移动;
CABasicAnimation 基本动画
基本属性:
- fromValue:动画的起始值;
- toValue:动画的结束值;
- byValue:在当前位置增加多少数值;
三个属性至少有两个不能为空。当byValue为空时,动画从fromValue到toValue执行运动;当toValue为空时,动画从fromValue到fromValue+byValue执行运动;当fromValue为空时,动画从toValue-byValue到toValue执行运动。
例子:模仿心动的动画
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
[button setImage:[UIImage imageNamed:@"heart"] forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
button.adjustsImageWhenHighlighted = NO;
[self.view addSubview:button];
}
-(void)buttonAction:(UIButton *)button
{
CALayer *scaleLayer = [[CALayer alloc] init];
//layer层添加图片
scaleLayer.contents = (id)[UIImage imageNamed:@"heart"].CGImage;
scaleLayer.frame = CGRectMake(0, 0, 50, 50);
[button.layer addSublayer:scaleLayer];
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.fillMode = kCAFillModeForwards;
scaleAnimation.repeatCount = 2;
scaleAnimation.duration = 0.8;
[scaleLayer addAnimation:scaleAnimation forKey:@"scaleAnimation"];
}
CAKeyframeAnimation 关键帧动画
基本属性:
- values:存放关键帧(keyframe),在动画执行期间,会逐个经过这些关键帧;
- path:动画的路径,CGPathRef或CGMutablePathRef类型,让层跟着路径移动。设置了path,values就不起作用了。path只对CALayer中的position移动起作用;
- keyTimes:可以为对应的关键帧取对应的时间点,其取值范围是0到1;keyTimes每一个时间值都对应values中的每一帧;当keyTimes没有设置的时候,各个关键帧直接的时间是平分的;
- timingFunctions:存放速度函数,控制动画运动的速度,类型如上;
- calculationMode:该属性决定图形在每个子路径下是跳着走还是匀速走,与timingFunctions属性类似;
calculationMode属性:
- kCAAnimationLinear:默认值,当关键帧为坐标点的时候,关键帧之间直接直线相连进行差值计算,线性;
- kCAAnimationDiscrete:离散,没有中间过程,直接在每个关键帧上逐个显示,keyTimes属性依旧生效,图形跳跃的出现在每一个关键帧上;
- kCAAnimationPaced:使动画匀速进行,设置的keyTimes和timingFunctions无效;
- kCAAnimationCubic:针对关键帧为坐标点时,对关键帧进行圆滑曲线相连,目的是使图形的运行轨迹变得圆滑;
- kCAAnimationCubicPaced:使图形的运行变得圆滑且匀速,设置的keyTimes和timingFunctions无效;
例子:心沿着轨迹运动
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CGFloat x = (375-50)/2;
CGFloat y = (667-80);
CALayer *animationLayer = [[CALayer alloc] init];
animationLayer.contents = (id)[UIImage imageNamed:@"heart"].CGImage;
animationLayer.frame = CGRectMake(x, y, 50, 50);
[self.view.layer addSublayer:animationLayer];
CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
keyframeAnimation.values = @[[NSValue valueWithCGPoint:CGPointMake(x, y)],[NSValue valueWithCGPoint:CGPointMake(x-25, y-50)],[NSValue valueWithCGPoint:CGPointMake(x+25, y-50-50)],[NSValue valueWithCGPoint:CGPointMake(x-25, y-50-50-50)],[NSValue valueWithCGPoint:CGPointMake(x+25, y-50-50-50-50)]];
keyframeAnimation.duration = 3;
keyframeAnimation.fillMode = kCAFillModeBoth;
keyframeAnimation.removedOnCompletion = NO;
keyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
keyframeAnimation.repeatCount = 1;
[animationLayer addAnimation:keyframeAnimation forKey:@"keyframeAnimation"];
}
CAAnimationGroup 动画组
动画组,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间。
基本属性:
- animations:数组,保存一组动画对象;
例子:缩放、平移、旋转组合起来的动画
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *groupLayer = [[CALayer alloc] init];
groupLayer.frame = CGRectMake(100, 100, 50, 50);
groupLayer.cornerRadius = 10;
groupLayer.backgroundColor = [UIColor orangeColor].CGColor;
[self.view.layer addSublayer:groupLayer];
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
scaleAnimation.toValue = [NSNumber numberWithFloat:1.5];
scaleAnimation.autoreverses = YES;
scaleAnimation.repeatCount = MAXFLOAT;
scaleAnimation.duration = 2;
CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
moveAnimation.fromValue = [NSValue valueWithCGPoint:groupLayer.position];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(320-80, groupLayer.position.y)];
moveAnimation.autoreverses = YES;
moveAnimation.repeatCount = MAXFLOAT;
moveAnimation.duration = 2;
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
rotateAnimation.fromValue = [NSNumber numberWithFloat:0.0];
rotateAnimation.toValue = [NSNumber numberWithFloat:6.0*M_PI];
rotateAnimation.autoreverses = YES;
rotateAnimation.repeatCount = MAXFLOAT;
rotateAnimation.duration = 2;
CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
groupAnimation.animations = @[scaleAnimation,moveAnimation,rotateAnimation];
groupAnimation.autoreverses = YES;
groupAnimation.repeatCount = MAXFLOAT;
groupAnimation.duration = 2;
[groupLayer addAnimation:groupAnimation forKey:@"groupAnimations"];
}
CATransition 转场动画
CAAnimation的子类,用于做转场动画,能够为层提供移除屏幕和移入屏幕的动画效果。
基本属性:
- type:过渡动画的类型,默认是fade;
- subtype:过渡动画的方向;
- startProgress:动画起点,在整体动画的百分比;
- endProgress:动画终点,在整体动画的百分比;
/* 过渡效果
fade //交叉淡化过渡(不支持过渡方向) kCATransitionFade
push //新视图把旧视图推出去 kCATransitionPush
moveIn //新视图移到旧视图上面 kCATransitionMoveIn
reveal //将旧视图移开,显示下面的新视图 kCATransitionReveal
cube //立方体翻滚效果
oglFlip //上下左右翻转效果
suckEffect //收缩效果,如一块布被抽走(不支持过渡方向)
rippleEffect //滴水效果(不支持过渡方向)
pageCurl //向上翻页效果
pageUnCurl //向下翻页效果
cameraIrisHollowOpen //相机镜头打开效果(不支持过渡方向)
cameraIrisHollowClose //相机镜头关上效果(不支持过渡方向)
*/
/* 过渡方向
kCATransitionFromRight
kCATransitionFromLeft
kCATransitionFromBottom
kCATransitionFromTop
*/
// CATransition的使用
CATransition *anim = [CATransition animation];
anim.type = @"cube"; // 动画过渡类型
anim.subtype = kCATransitionFromTop; // 动画过渡方向
anim.duration = 1; // 动画持续1s
// 代理,动画执行完毕后会调用delegate的animationDidStop:finished:
anim.delegate = self;