美文网首页核心动画
CoreAnimation详解(一)有关Layer的动画

CoreAnimation详解(一)有关Layer的动画

作者: smallLabel | 来源:发表于2015-11-05 12:04 被阅读1970次

    原文链接:http://blog.csdn.net/hello_hwc/article/details/43112379

    我的IOS SDK详解专栏,地址

    http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html

    本文主要从CoreAnimation的Layer角度来讲解动画,我想从

    CALayer的角度更好理解,后续还会有第二篇从UIKIt的UIView角度来讲解动画,第三篇讲解UIDynamicAnimation,第三篇我

    会讲到UIViewController切换时候的动画。

    本文主要涵盖四个部分

    1.基础动画-会讲到时间函数和一些关键的属性

    2.基于关键帧的动画-讲到沿着指定路径运行的动画

    3.动画组-多个动画组合到一起形成复杂的动画

    4.简单讲一下讲一下有关动画的代理

    (一)为什么要设计动画?

    动画提供了一个渐变的方式来表达变化,使用动画可以避免各种界面突变,造成用户困惑。

    IOS中,使用CoreAnimation只要指定始末状态或者关键帧的状态,CoreAnimation会高效的为我们创建补间动画。

    (二)从CALayer的角度来看的三种动画

    首先不熟悉CALayer的同学看看前两篇的CALayer的内容,这是CoreAnimation的基础。这里我重复的介绍两种CALayer的Tree。

    Presentation Tree-对应在动画的过程中,CALayer的属性

    Model Tree-对应CALayer的实际属性。

    通过使用 -[CALayer presentationLayer] 和 -[CALayer modelLayer]可以访问两种Tree

    动画的过程实际上是修改Presentation Tree

    2.1 基础的动画

    第一个简单的动画,我希望imageview向右移动100的距离,移动方式easeInOut(加速开始,减速结束)。



    代码如下,通常有两种方式来影响动画

    [objc]view plaincopy

    CABasicAnimation* animation = [CABasicAnimation animation];

    animation.keyPath=@"position.x";//KVC的方式来访问属性

    animation.fromValue= @(self.imageview.layer.position.x);//该属性开始的值

    animation.toValue= @(self.imageview.layer.position.x+100);//结束的值

    animation.duration=1;//持续时间

    animation.timingFunction= [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];//结束函数

    [self.imageview.layeraddAnimation:animationforKey:@"basic"];//添加动画

    通过fromValue和toValue是一种方式,当然也可以通过byValue的方式,byValue在初值上加上byValue的变化,通过以下代码也可以实现上述动画

    [objc]view plaincopy

    CABasicAnimation* animation = [CABasicAnimationanimation];

    animation.keyPath=@"position.x";

    animation.byValue= @(100);

    animation.duration=1;

    animation.timingFunction= [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    [self.imageview.layeraddAnimation:animationforKey:@"basic"];

    但是,结束后会发现,imageview又恢复到原处。这是因为在动画的过程中,我们修改的是Presentation Tree,并没有实际修改CALayer的属性。想要让动画停在结束的位置,通常有两种方式,

    (1)修改属性

    代码如下

    [objc]view plaincopy

    CABasicAnimation* animation = [CABasicAnimationanimation];

    animation.keyPath=@"position.x";

    animation.fromValue= @(self.imageview.layer.position.x);

    animation.toValue= @(self.imageview.layer.position.x+100);

    animation.duration=1;

    animation.timingFunction= [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    [self.imageview.layeraddAnimation:animationforKey:@"basic"];

    self.imageview.layer.position= CGPointMake(self.imageview.layer.position.x+100,self.imageview.layer.position.y);

    (2)设置让动画停在结束的位置

    [objc]view plaincopy

    CABasicAnimation* animation = [CABasicAnimationanimation];

    animation.keyPath=@"position.x";

    animation.fromValue= @(self.imageview.layer.position.x);

    animation.toValue= @(self.imageview.layer.position.x+100);

    animation.duration=1;

    animation.timingFunction= [CAMediaTimingFunctionfunctionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    animation.removedOnCompletion=NO;//动画结束了禁止删除

    animation.fillMode= kCAFillModeForwards;//停在动画结束处

    [self.imageview.layeraddAnimation:animationforKey:@"basic"];

    一般采用前者,因为动画往往的结束是实际的属性的改变。

    这里再讲解下时间函数

    时间函数决定了动画如何执行,时间函数决定了动画的数学模型,比如速度速度最好不要有突变, 系统提供的时间函数有以下几种

    NSString*constkCAMediaTimingFunctionLinear;线性

    NSString*constkCAMediaTimingFunctionEaseIn;加速进入

    NSString*constkCAMediaTimingFunctionEaseOut;减速停止

    NSString*constkCAMediaTimingFunctionEaseInEaseOut;加速进入减速停止,这个是常用的

    NSString*constkCAMediaTimingFunctionDefault;默认

    当然,时间函数支持自定义,用如下函数

    functionWithControlPoints::::

    这个函数的4个点决定了一个三维的贝塞尔曲线来决定时间函数。这里不深入讲解了。

    最后,这一点尤为重要,就是在传递CAAnimation的对象或者子类给Layer的时候,传递的是copy

    2.2 基于关键帧的动画

    以下是一个基于关键帧创建的抖动的动画,采用在时间点对应的位置来创建动画

    [objc]view plaincopy

    CAKeyframeAnimation* animation = [CAKeyframeAnimationanimation];

    animation.keyPath=@"position.x";

    NSInteger initalPositionX =self.imageview.layer.position.x;

    animation.values= @[@(initalPositionX),

    @(initalPositionX +10),

    @(initalPositionX -10),

    @(initalPositionX +10),

    @(initalPositionX)];

    animation.keyTimes= @[

    @(0),

    @(1/6.0),

    @(3/6.0),

    @(5/6.0),

    @(1)];

    [self.imageview.layeraddAnimation:animationforKey:@"keyFrame"];

    当然,基于关键帧的动画支持沿着路径运动,可以设置时间函数来决定运动的方式

    例如以下创建一个比较复杂的运动,首先移动到(200,200),然后沿着以该点为圆心,逆时针旋转半圈,最后停在结束的位置。

    动画的过程中,imageview沿着路径转动

    [objc]view plaincopy

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animation];

    animation.keyPath=@"position";

    //Create Path

    CGMutablePathRef mutablepath = CGPathCreateMutable();

    CGPathMoveToPoint(mutablepath,nil,self.imageview.layer.position.x,self.imageview.layer.position.y);

    CGPathAddLineToPoint(mutablepath,nil,200,200);

    CGPathAddArc(mutablepath,nil,200,200,100,0,M_PI,YES);

    //set path

    animation.path= mutablepath;

    animation.duration=4.0;

    animation.rotationMode= kCAAnimationRotateAuto;

    animation.removedOnCompletion=NO;//动画结束了禁止删除

    animation.fillMode= kCAFillModeForwards;//停在动画结束处

    [self.imageview.layeraddAnimation:animationforKey:@"PathAnimation"];




    2.3 动画组

    所谓,动画组就是把几个动画组合到一起,然后一起执行,通常复杂的动画都是由动画组来实现的。

    举个例子:沿着上个例子的路径运动,运动的同时透明度渐变。

    [objc]view plaincopy

    CAKeyframeAnimation* pathAnimation = [CAKeyframeAnimationanimation];

    pathAnimation.keyPath=@"position";

    //Create Path

    CGMutablePathRef mutablepath = CGPathCreateMutable();

    CGPathMoveToPoint(mutablepath,nil,self.imageview.layer.position.x,self.imageview.layer.position.y);

    CGPathAddLineToPoint(mutablepath,nil,200,200);

    CGPathAddArc(mutablepath,nil,200,200,100,0,M_PI,YES);

    //set path

    pathAnimation.path= mutablepath;

    pathAnimation.rotationMode= kCAAnimationRotateAuto;

    [self.imageview.layeraddAnimation:pathAnimationforKey:@"PathAnimation"];

    //透明度变化

    CAKeyframeAnimation* opacityAnimation = [CAKeyframeAnimationanimation];

    opacityAnimation.keyPath=@"opacity";

    opacityAnimation.values= @[@(1.0),

    @(0.5),

    @(0.0),

    @(0.5),

    @(1.0)];

    opacityAnimation.calculationMode= kCAAnimationPaced;

    [self.imageview.layeraddAnimation:opacityAnimationforKey:@"OpacityAnination"];

    //配置动画组

    CAAnimationGroup* animationGroup = [[CAAnimationGroupalloc]init];

    animationGroup.animations= @[pathAnimation,opacityAnimation];

    animationGroup.duration=4.0;

    animationGroup.removedOnCompletion=NO;

    animationGroup.fillMode= kCAFillModeBackwards;

    [self.imageview.layeraddAnimation:animationGroupforKey:@"GroupAnimation"];

    效果的几幅截图如图





    (三)动画的代理

    通过设置代理可以监听动画开始和结束的事件

    通过设置delegate,来监听两个函数

    animationDidStart:(CAAnimation*)anim

    animationDidStop:(CAAnimation*)anim finished:(BOOL)flag

    这里的flag判断动画是否执行完毕

    最后,附上wiki上设计动画的12个基本原则

    https://en.wikipedia.org/wiki/12_basic_principles_of_animation

    相关文章

      网友评论

        本文标题: CoreAnimation详解(一)有关Layer的动画

        本文链接:https://www.haomeiwen.com/subject/dfqchttx.html