iOS CAAnimation动画

2017-06-28  本文已影响284人  谢谢生活

CAAnimation

CAAnimation 是一个抽像类。CAAnimation 也派生出了很多子类,我们使用动画,其实也是使用他得子类。

CAAnimation 是所有动画的父类。

子类三个:



一:基本概念

什么是Animation(动画),简单点说就是在一段时间内,显示的内容发生了变化.对CALayer来说就是在一段时间内,其Animatable Property发生了变化.从CALayer(CA = Core Animation)类名来看就可以看出ios的Layer就是为动画而生的,便于实现良好的交互体验. 这里涉及到两个东西: 一是Layer(基类CALayer),一是Animation(基于CAAnimation). Animation作用于Layer.CALayer提供了接口用于给自己添加Animation. 用于显示的Layer本质上讲是一个Model,包含了Layer的各种属性值. Animation则包含了动画的时间,变化,以及变化的速度.下面分别详细讲解Layer和Animation相关知识.

二:CALayer及时间模型

我们都知道UIView是MVC中的View.UIView的职责在于界面的显示和界面事件的处理.每一个View的背后都有一个layer(可以通过view.layer进行访问),layer是用于界面显示的.CALayer属于QuartzCore框架,非常重要,但并没有想象中的那么好理解.我们通常操作的用于显示的Layer在Core Animation这层的概念中其实担当的是数据模型Model的角色,它并不直接做渲染的工作.关于Layer,之前从座标系的角度分析过,这次则侧重于它的时间系统.

subLayer = [[CALayer alloc] init]; subLayer.frame = CGRectMake(0, 0, 300, 300); subLayer.backgroundColor = [[UIColor redColor] CGColor]; [self.view.layer addSublayer:subLayer];

所有的非Root Layer在设置Animatable Properties的时候都存在着隐式动画,默认的duration是0.25秒.
subLayer.position = CGPointMake(300,400);
像上面这段代码当下一个RunLoop开始的时候并不是直接将subLayer的position变成(300,400)的,而是有个移动的动画进行过渡完成的.
任何Layer的animatable属性的设置都应该属于某个CA事务(CATransaction),事务的作用是为了保证多个animatable属性的变化同时进行,不管是同一个layer还是不同的layer之间的.CATransaction也分两类,显式的和隐式的,当在某次RunLoop中设置一个animatable属性的时候,如果发现当前没有事务,则会自动创建一个CA事务,在线程的下个RunLoop开始时自动commit这个事务,如果在没有RunLoop的地方设置layer的animatable属性,则必须使用显式的事务.
显式事务的使用如下:
[CATransaction begin];... [CATransaction commit];
事务可以嵌套.当事务嵌套时候,只有当最外层的事务commit了之后,整个动画才开始.
可以通过CATransaction来设置一个事务级别的动画属性,覆盖隐式动画的相关属性,比如覆盖隐式动画的duration,timingFunction.如果是显式动画没有设置duration或者timingFunction,那么CA事务设置的这些参数也会对这个显式动画起作用.
还可以设置completionBlock,当当前CATransaction的所有动画执行结束后, completionBlock会被调用.

-(void)pauseLayer:(CALayer*)layer{ 
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer{
CFTimeInterval pausedTime = [layer timeOffset]; layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}

三: 显式动画Animation

当需要对非Root Layer进行动画或者需要对动画做更多自定义的行为的时候,就必须使用到显式动画了,显式动画的基类为CAAnimation,常用的是CABasicAnimation,CAKeyframeAnimation有时候还会使用到CAAnimationGroup,CATransition(注意不是CATransaction,Transition是过渡的意思).

集成链

1):基础动画 CABasicAnimation

+ (id)functionWithName:(NSString *)name;

+ (id)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

- (id)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;

五种预定义的时间函数名字的常量变量分别为

kCAMediaTimingFunctionLinear, 
kCAMediaTimingFunctionEaseIn, 
kCAMediaTimingFunctionEaseOut, 
kCAMediaTimingFunctionEaseInEaseOut, 
kCAMediaTimingFunctionDefault. 

下图展示了前面四种Timing Function的曲线图,横座标表示时间,纵座标表示变化量,这点需要搞清楚(并不是平面座标系中xy).



自定义的Timing Function的函数图像就是一条三次贝塞尔曲线Cubic Bezier Curve,贝塞尔曲线的优点就是光滑,用在这里就使得变化显得光滑.一条三次贝塞尔曲线可以由起点终点以及两个控制点决定.
上面的kCAMediaTimingFunctionDefault对应的函数曲线其实就是通过[(0.0,0.0), (0.25,0.1), (0.25,0.1), (1.0,1.0)]这四个点决定的三次贝塞尔曲线,头尾为起点和终点,中间的两个点是控制点.


上图中P0是起点,P3是终点,P1和P2是两个控制点

如果时间变化曲线既不是直线也不是贝塞尔曲线,而是自定义的,又或者某个图层运动的轨迹不是直线而是一个曲线,这些是基本动画无法做到的,所以引入下面的内容,CAKeyframeAnimation,也即所谓的关键帧动画.

    CABasicAnimation * animation = [CABasicAnimation animation];
    animation.keyPath = @"position";
    animation.duration = 2;
    animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(80, 80)];
    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 30)];
     animation.repeatCount = CGFLOAT_MAX;
    //是否动画完成就移除模型图层
    animation.removedOnCompletion = NO;
    //动画填充模式
    animation.fillMode = kCAFillModeForwards;
    [_myview.layer addAnimation:animation forKey:nil];

 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];  
    animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(_demoView.center.x, _demoView.center.y)];  //可以省略...  
    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(270, 410)];  
    animation.duration = 3.0f;  
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];    //动画速度设置  
      
    [_demoView.layer addAnimation:animation forKey:nil];  

2)关键帧动画 CAKeyframeAnimation

CABasicAnimation其实可以看作一种特殊的关键帧动画,只有头尾两个关键帧.

kCAAnimationLinear 
kCAAnimationDiscrete 
kCAAnimationPaced 
kCAAnimationCubic 
kCAAnimationCubicPaced
CAKeyframeAnimation *anima = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSValue *value0 = [NSValue valueWithCGPoint:CGPointMake(0, SCREEN_HEIGHT/2-50)];
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2-50)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2+50)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2+50)];
    NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2-50)];
    NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50)];
    anima.values = [NSArray arrayWithObjects:value0,value1,value2,value3,value4,value5, nil];
    anima.duration = 2.0f;
      //用系统最大的cgfloat作为重复次数,但是当界面刷新后就没有动画效果了,因为没有加入消息循环队列,要想实现UI刷新后依然有动画鲜果建议使用displayLink,原理和NSTimer加入消息循环队列一样的
     anima.repeatCount = CGFLOAT_MAX;
 anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];//设置动画的节奏
    anima.delegate = self;//设置代理,可以检测动画的开始和结束
    [_demoView.layer addAnimation:anima forKey:@"keyFrameAnimation"];

UIBezierPath *path = [UIBezierPath bezierPath];  
    [path moveToPoint:_demoView.center];    //一定要设置 不然底层的CGPathRef找不到起始点,将会崩溃  
    [path addCurveToPoint:CGPointMake(270, 410) controlPoint1:CGPointMake(0, Screen_Height) controlPoint2:CGPointMake(Screen_Width, 0)];    //以左下角和右上角为控制点  
      
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];  
    animation.path = path.CGPath;  
    animation.duration = 3.0f;  
    animation.removedOnCompletion = NO;  
    animation.fillMode = kCAFillModeForwards;  
      
    [_demoView.layer addAnimation:animation forKey:nil];  

四:动画组CAAnimationGroup

 // 位移动画
    CAKeyframeAnimation *anima1 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSValue *value0 = [NSValue valueWithCGPoint:CGPointMake(0, SCREEN_HEIGHT/2-50)];
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2-50)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2+50)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2+50)];
    NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2-50)];
    NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50)];
    anima1.values = [NSArray arrayWithObjects:value0,value1,value2,value3,value4,value5, nil];
    anima1.removedOnCompletion = NO;
    anima1.fillMode = kCAFillModeBoth;
    anima1.beginTime = 2;
    anima1.duration = 2;
    //缩放动画
    CABasicAnimation *anima2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    anima2.fromValue = [NSNumber numberWithFloat:0.1f];
    anima2.toValue = [NSNumber numberWithFloat:2.0f];
    anima2.removedOnCompletion = NO;
    anima2.fillMode = kCAFillModeForwards;
    anima2.beginTime = 2;
    //旋转动画
    CABasicAnimation *anima3 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    anima3.toValue = [NSNumber numberWithFloat:M_PI*4];
    anima3.removedOnCompletion = NO;
    anima3.fillMode = kCAFillModeForwards;
    //组动画
//    如果fillMode=kCAFillModeForwards和removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变
    CAAnimationGroup *groupAnimation = [CAAnimationGroup animation];
    groupAnimation.animations = [NSArray arrayWithObjects:anima1,anima2,anima3, nil];
    groupAnimation.duration = 4.0f;
    groupAnimation.removedOnCompletion = NO;
    groupAnimation.fillMode = kCAFillModeForwards;
    [_demoView.layer addAnimation:groupAnimation forKey:@"groupAnimation"];
   // 一个layer设定了很多动画,他们都会同时执行,而且是顺序执行。

五:CATransition转成动画。


//官方推荐的 可用
//kCATransitionFade //淡入淡出 (不支持过渡方向)
//kCATransitionPush, //推挤
//kCATransitionReveal //揭开
//kCATransitionMoveIn //覆盖
//非官方推荐 谨慎使用,有些不能上线的
//Cube //立方体
//SuckEffect //吮吸
//OglFlip //翻转
//rippleEffect //波纹
//pageCurl //翻页
//pageUnCurl //反翻页
//cameraIrisHollowOpen //开镜头 相机镜头打开效果(不支持过渡方向)
//cameraIrisHollowClose //关镜头 相机镜头打开效果(不支持过渡方向)



CA_EXTERN NSString * const kCATransitionFromRight
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);//右
CA_EXTERN NSString * const kCATransitionFromLeft
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);//左
CA_EXTERN NSString * const kCATransitionFromTop//顶
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);
CA_EXTERN NSString * const kCATransitionFromBottom//底部
CA_AVAILABLE_STARTING (10.5, 2.0, 9.0, 2.0);


    CATransition *animation = [CATransition animation];
    //设置运动时间
    animation.duration = DURATION;
    //设置运动type
    animation.type = kCATransitionMoveIn;//非官方推荐的自能使用字符串@“fade”
    animation.subtype = kCATransitionFromRight;
  
    //设置运动速度
    animation.timingFunction = UIViewAnimationOptionCurveEaseInOut;
    [self.myView.layer addAnimation:animation forKey:@"animation"];
上一篇 下一篇

猜你喜欢

热点阅读