美文网首页
Core Animation 四 : CAAnimation

Core Animation 四 : CAAnimation

作者: Trigger_o | 来源:发表于2021-01-19 18:12 被阅读0次
    CAAnimation结构

    CAAnimation作为父类,实现动画时是不直接使用的,直接看它的子类.
    CAPropertyAnimation仍然是一个父类,也是不直接使用的.
    但是它们的方法子类都会用,下面会说到.

    一. CABasicAnimation

    CAAnimation中最常用的类
    打开文档,在CALayer的属性中,经常可以看到这个描述"Animatable",凡是带这种描述的,都可以在CAPropertyAnimation中使用,意思就是制作这些属性的动画,比如opacity, bounds,position, transform等等;由此可见PropertyAnimation这个名字取得也是很到位.


    Animatable
        _l = [CALayer layer];
        _l.backgroundColor = UIColor.lightGrayColor.CGColor;
        _l.frame = CGRectMake(20, 100, ScreenWidth - 40, ScreenWidth - 40);
        [self.view.layer addSublayer:_l];
    
    - (IBAction)onPressBtn:(id)sender {
        CABasicAnimation *anime = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
        anime.fromValue = (__bridge id)_l.backgroundColor;
        anime.toValue = (__bridge id)UIColor.orangeColor.CGColor;
        anime.duration = .5;
        anime.fillMode = kCAFillModeForwards;
        //anime.repeatCount = 4;
        //anime.repeatDuration = 10;
        //anime.cumulative = YES;
        anime.removedOnCompletion = NO;
        [self.l addAnimation:anime forKey:@"an1"];
    }
    

    *+(instancetype)animationWithKeyPath:(nullable NSString )path;
    这是CAPropertyAnimation的方法,用于创建一个CAPropertyAnimation对象或者子类对象,path就是CALayer的属性,
    动画一定是在layer层,上面这个例子,把layer换成view,改成[self.v.layer addAnimation:anime]也是一样的.

    fromValue和toValue很好理解,从动画开始到动画结尾,两个值,还有个byValue,三个属性的组合后面详细说.
    duration是动画持续的时长

    fillMode和removedOnCompletion需要组合使用,removedOnCompletion指的是在动画完成后是否移除动画,也就是上面这个anime对象,默认为YES.当动画结束后,layer又回到原来的样子.
    当设置为NO时,layer也回到原来的样子,不过此时fillMode就会生效,如果设置了fillMode,就不一样了

    • fillMode有四种值
      kCAFillModeForwards:
      当动画结束后,layer将保持现在的样子.
      kCAFillModeBackwards:
      在上面的例子中,fromValue设置成了_l.backgroundColor,这时动画的初始颜色和layer本来的颜色是一样的,既然有fromValue这个东西,那么它就可以设置成各种颜色,假如是绿色,那动画开始时就会先突然变成绿色,然后再渐变成橙色;使用kCAFillModeBackwards的时候,当动画被添加到layer上时,会立即变成fromValue,等待执行动画
      kCAFillModeBoth:
      同时包含Forwards和Backwards,当动画被添加到layer上时,立即变成fromValue,当动画执行完的时候,一直保存toValue
      kCAFillModeRemoved:
      默认值,和removedOnCompletion为NO时效果一样.

    repeatCount和repeatDuration
    repeatCount是重复次数,repeatDuration是在一个时间内持续重复执行动画,单位是秒
    如果这两个同时不为0,那么repeatCount的优先级更高,repeatDuration则不会生效.

    cumulative
    这个属性在有repeat的情况下会生效,如果设置为yes,那么一次动画结束后,会把变换值累积到下一轮,看图比较直接,
    下面这两个都是position动画,注意因为cumulative为YES是累加keyPath的值,所以如果position的fromValue不是(0,0),那么动画就会跳着走

    cumulative为NO,fromValue为(100,100)
    cumulative为YES, fromValue为(0,0)

    CABasicAnimation的基础内容就这些,最重要的是各种path,标注了"Animatable"的属性都可以执行动画,CALayer的子类如CAGradientLayer,CATextLayer等等也有很多属性是Animatable的.
    因为是keyPath,所以可以写多层,还有一些便捷的keyPath,下面列出一些除了Animatable之外的keypath

    //缩放
    //    CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    //    an2.fromValue = @(1.0);
    //    an2.toValue = @(0.5);
        
    //x轴缩放
    //    CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
    //    an2.fromValue = @(1.0);
    //    an2.toValue = @(0.5);
        
    //平面旋转
    //    CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //    an2.fromValue = @(.0);
    //    an2.toValue = @(M_PI_2);
        
    //边框
    //    CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
    //    an2.fromValue = @(.0);
    //    an2.toValue = @(150.0);
        
    //position
    //    CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"position"];
    //    an2.fromValue = [NSValue valueWithCGPoint:self.v.layer.position];
    //    an2.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
        
    //contents
        CABasicAnimation *an2 = [CABasicAnimation animationWithKeyPath:@"contents"];
        an2.fromValue = self.v.layer.contents;
        an2.toValue = (id)[UIImage imageNamed:@"rocket"].CGImage;
        an2.duration = .5;
        an2.fillMode = kCAFillModeForwards;
        an2.removedOnCompletion = NO;
        [self.v.layer addAnimation:an2 forKey:@"an1"];
    
    //mask,shadowColor,shadowOffset,shadowOpacity,shadowRadius等等
    

    fromValue,toValue和byValue
    • Both fromValue and toValue are non-nil. Interpolates between fromValue and toValue.
    如果设置了fromValue和toValue,那么动画的过程是在这两个值进行插值
    • fromValue and byValue are non-nil. Interpolates between fromValue and (fromValue + byValue).
    如果设置了fromValue和byValue,那么动画的过程是在fromValue和(fromValue + byValue)进行插值
    • byValue and toValue are non-nil. Interpolates between (toValue - byValue) and toValue.
    如果设置了toValue和byValue,那么动画的过程是在(toValue - byValue) 和toValue进行插值
    • fromValue is non-nil. Interpolates between fromValue and the current presentation value of the property.
    如果只设置了fromValue,那么在初始值和fromValue直接插值
    • toValue is non-nil. Interpolates between the current value of keyPath in the target layer’s presentation layer and toValue.
    如果只设置了toValue,那么在初始值和toValue直接插值
    • byValue is non-nil. Interpolates between the current value of keyPath in the target layer’s presentation layer and that value plus byValue.
    如果只设置了byValue,那么在初始值和(初始值+byValue)直接插值
    • All properties are nil. Interpolates between the previous value of keyPath in the target layer’s presentation layer and the current value of keyPath in the target layer’s presentation layer.
    如果都没设置,那就没有动画

    二. CAKeyframeAnimation

    CAKeyframeAnimation帧动画
    它有两种特性,一是可以定义一个path路径,作为layer在父层上移动的路径,执行动画.
    二是CAKeyframeAnimation是CAPropertyAnimation的子类,所以它也有keyPath,结合CAKeyframeAnimation的values属性,也是一种帧动画,CABasicAnimation只能从A到B,而CAKeyframeAnimation可以A->B->...->N.
    所谓帧动画,就是定义一组动画的各个关键帧,对动画本身是什么样的动画,变换也好,颜色也好,bounds,position,边框,圆角等等,都可以是帧动画;CAKeyframeAnimation提供的path属性,是专门为平移变换扩展的.

    还是用背景颜色举例子

        CAKeyframeAnimation *an = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"];
        an.duration = 3.0;
        an.values = @[(id)UIColor.lightGrayColor.CGColor,(id)UIColor.orangeColor.CGColor,(id)UIColor.blueColor.CGColor];
        an.keyTimes = @[@(0),@(0.5),@1];
        an.fillMode = kCAFillModeForwards;
        an.removedOnCompletion = NO;
        [self.v.layer addAnimation:an forKey:nil];
    

    CAKeyframeAnimation和CABasicAnimation都没有独立的构造方法,都是使用父类的构造方法animationWithKeyPath
    keyTimes是动画的时间节点,在某个时间点进行某个值的变化,实质是总时长的百分比,每个数字都是取值0-1,并且后面的要大于前面的.
    values是对应时间节点的值
    建议第一个数是0.并且values第一个值是初始状态,这样可以平滑过渡.

    当使用path时

        UIBezierPath *be = [UIBezierPath bezierPath];
        [be moveToPoint:self.v.layer.position];
        [be addCurveToPoint:CGPointMake(200, 900) controlPoint1:CGPointMake(20, 400) controlPoint2:CGPointMake(400, 600)];
        CAKeyframeAnimation *an = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        an.duration = 3.0;
        an.path = be.CGPath;
        an.calculationMode = kCAAnimationLinear;
        an.rotationMode = kCAAnimationRotateAuto;
        an.removedOnCompletion = NO;
        an.fillMode = kCAFillModeForwards;
        //an.keyTimes = @[@0,@.1,@.2,@.8,@.9,@1];
        [self.v.layer addAnimation:an forKey:@"an"];
    

    1.使用path时,如果设置keyTimes,那么至少需要6个元素
    2.rotationMode会使layer在动画时改变方向,像行驶的汽车一样,实时与路径切线平行

    (For layer properties that contain a CGPoint data type, the path object you assign to this property defines the values for that property over the length of the animation. If you specify a value for this property, any data in the values property is ignored.)
    3.path指定了动画的路径,一旦设置了path,values就不再生效.

    (Any timing values you specify for the animation are applied to the points used to create the path. Paths can contain points defining move-to, line-to, or curve-to segments. The end point of a line-to or curve-to segment defines the keyframe value. All other points between that end value and the previous value are then interpolated. Move-to segments do not define separate keyframe values.)
    4.keyTimes可以影响到动画的插值计算,但是前提calculationMode不能是kCAAnimationPaced或者kCAAnimationCubicPaced,并且第一个数必须是0.0,最后一个数必须是1.0

    (How the animation proceeds along the path is dependent on the value in the calculationMode property. To achieve a smooth, constant velocity animation along the path, set the calculationMode property to kCAAnimationPaced or kCAAnimationCubicPaced. To create an animation where the location value jumps from keyframe point to keyframe point (without interpolation in between), use the kCAAnimationDiscrete value. To animate along the path by interpolating values between points, use the kCAAnimationLinear value.)
    5.动画的运动方式由calculationMode决定,需要跳跃的移动,使用kCAAnimationDiscrete;需要普通的线性运动使用kCAAnimationLinear;需要平滑的过渡和衔接使用kCAAnimationPaced或者kCAAnimationCubicPaced,想让一个循环的动画能平滑的首尾相连就需要这个;

     _v = [UIView new];
        _v.backgroundColor = UIColor.lightGrayColor;
        _v.frame = CGRectMake(20, 100, 100, 100);
        _v.center = CGPointMake(ScreenWidth/2 + 100 , ScreenHeight/2);
        [self.view addSubview:_v];
    
    - (IBAction)onPressBtn2:(id)sender {
        UIBezierPath *be = [UIBezierPath bezierPath];
        [be moveToPoint:self.v.layer.position];
        [be addArcWithCenter:CGPointMake(ScreenWidth/2, ScreenHeight/2) radius:100 startAngle:0 endAngle:2 * M_PI clockwise:YES];
        CAKeyframeAnimation *an = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        an.duration = 3.0;
        //an.keyTimes = @[@0,@.1,@.2,@.8,@.9,@1];
        an.path = be.CGPath;
        //an.calculationMode = kCAAnimationLinear;
        an.calculationMode = kCAAnimationPaced;
        an.repeatCount = CGFLOAT_MAX;
        an.rotationMode = kCAAnimationRotateAutoReverse;
        an.removedOnCompletion = NO;
        an.fillMode = kCAFillModeForwards;
        [self.v.layer addAnimation:an forKey:@"an"];
    }
    
    kCAAnimationLinear 并且设置keyTimes kCAAnimationPaced 并且不设置keyTimes

    ** CAMediaTimingFunction**
    CAKeyframeAnimation对象有两个属性timingFunction和timingFunctions,timingFunctions是一个数组,数组每一个元素都是一段时间控制函数,元素的个数与keyTimes个数相对应,例如keyTimes是@[@0,@.5,@1],那么timingFunctions需要有两个元素来描述0-0.5和0.5-1.0这两段时间内,keyPath值的变化函数.听起来非常绕,简单理解就是定义每一段动画的速度,如何加速,如何减速等等.
    timingFunctions数组的元素是CAMediaTimingFunction对象,实质就是上面说到的变化函数
    CAMediaTimingFunction提供了两构造方法,一种是使用系统预设的方案,另一种是自定义三次贝塞尔曲线函数

    • 使用系统预设的函数
      +(instancetype)functionWithName:(CAMediaTimingFunctionName)name;
      CAMediaTimingFunctionName有五种:
      kCAMediaTimingFunctionDefault 默认,没有特别的效果,用来稳定动画执行,防止出错
      kCAMediaTimingFunctionEaseIn 淡入,先缓后急
      kCAMediaTimingFunctionEaseInEaseOut 淡入淡出
      kCAMediaTimingFunctionEaseOut 淡出 先急后缓
      kCAMediaTimingFunctionLinear 匀速

    • 自定义三次贝塞尔曲线
      +(instancetype)functionWithControlPoints::::

      -(instancetype)initWithControlPoints::::
      参数是贝塞尔曲线的两个控制点,x1,y1,x2,y2

        UIBezierPath *be = [UIBezierPath bezierPath];
        [be moveToPoint:self.v.layer.position];
        [be addArcWithCenter:CGPointMake(ScreenWidth/2, ScreenHeight/2) radius:100 startAngle:0 endAngle:2 * M_PI clockwise:YES];
        CGPathRef path = CGPathCreateWithEllipseInRect(CGRectMake(ScreenWidth/2-100, ScreenWidth/2-100, 100, 100), nil);
        CAKeyframeAnimation *an = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        an.duration = 3.0;
        an.keyTimes = @[@0,@.1,@.2,@.8,@.9,@1];
        CAMediaTimingFunction *f1 = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        CAMediaTimingFunction *f2 = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        CAMediaTimingFunction *f3 = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        CAMediaTimingFunction *f4 = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        CAMediaTimingFunction *f5 = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        an.timingFunctions = @[f1,f2,f3,f4,f5];
        an.path = path;
        an.calculationMode = kCAAnimationLinear;
    //    an.repeatCount = CGFLOAT_MAX;
    //    an.repeatDuration = 10000;
        an.rotationMode = kCAAnimationRotateAuto;
        an.removedOnCompletion = NO;
        an.fillMode = kCAFillModeForwards;
        [self.v.layer addAnimation:an forKey:@"an"];
    
    CAMediaTimingFunction效果

    还有一个valueFunction的属性是对values的定义,决定了如何计算插值.

    三. CASpringAnimation

    CASpringAnimation弹性动画,可以详细定义弹性动画的各种特征.
    继承自CABasicAnimation,增加了5个属性

    • damping
      The default value of the damping property is 10. Reducing this value reduces the energy loss with each oscillation: the animated value will overshoot the toValue and the settlingDuration may be greater than the duration. Increasing the value increases the energy loss with each duration: there will be fewer and smaller oscillations and the settlingDuration may be smaller than the duration.
      阻尼,默认值是10,描述弹性的能量衰减速度,值越大,衰减越快,回弹次数越少

    • initialVelocity
      Defaults to 0, which represents an unmoving object. Negative values represent the object moving away from the spring attachment point, positive values represent the object moving towards the spring attachment point.
      初速度,默认是0,描述弹性的初速度,负值表示以一个初速度拉伸弹簧,正值表示以一个初速度压缩弹簧

    • mass
      The default mass is 1. Increasing this value will increase the spring effect: the attached object will be subject to more oscillations and greater overshoot, resulting in an increased settlingDuration. Decreasing the mass will reduce the spring effect: there will be fewer oscillations and a reduced overshoot, resulting in a decreased settlingDuration.
      质量,默认是1,增大质量会增大振幅和回弹次数

    • stiffness
      The default stiffness coefficient is 100. Increasing the stiffness reduces the number of oscillations and will reduce the settling duration. Decreasing the stiffness increases the the number of oscillations and will increase the settling duration.
      刚度,默认是100,就是弹簧有多硬,增大刚度会增大回弹的速度,刚度小,去的时候快,回来的时候慢

    • settlingDuration
      沉降时间,这个是只读的,上面四个属性,都会影响这个值,它与动画持续的时间duration是不相关的,但是duration优先级高,如果最终settlingDuration大于duration,动画会突兀的停止,而且停留位置并不是目标位置,所以可以这么写an2.duration = an2.settlingDuration;

    CASpringAnimation *an2 = [CASpringAnimation animationWithKeyPath:@"position"];
        an2.mass = 120;
        an2.initialVelocity = 5;
        an2.damping = 500;
        an2.stiffness = 1000;
        CGPoint from = self.v.layer.position;
        an2.fromValue = [NSValue valueWithCGPoint:from];
        an2.toValue = [NSValue valueWithCGPoint:CGPointMake(150, from.y)];
        an2.duration = an2.settlingDuration;
        an2.fillMode = kCAFillModeForwards;
        an2.removedOnCompletion = NO;
        [self.v.layer addAnimation:an2 forKey:@"an1"];
    
    弹性动画

    关于定制详细的帧动画和弹性动画,popAnimation封装了很多实用的方法

    四. CAAnimationGroup

    动画组,可以定义一组动画,按照时间节点执行.
    继承自CAAnimation,只增加了一个属性animations

    CAKeyframeAnimation *an = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"];
        an.calculationMode = kCAAnimationPaced;
        an.values = @[(id)UIColor.lightGrayColor.CGColor,(id)UIColor.orangeColor.CGColor,(id)UIColor.blueColor.CGColor,(id)UIColor.lightGrayColor.CGColor];
        an.keyTimes = @[@(0),@(0.33),@(.66),@(.1)];
    //    [self.v.layer addAnimation:an forKey:@"an1"];
        
        UIBezierPath *be = [UIBezierPath bezierPath];
        [be moveToPoint:self.v.layer.position];
        [be addArcWithCenter:CGPointMake(ScreenWidth/2, ScreenHeight/2) radius:100 startAngle:0 endAngle:2 * M_PI clockwise:YES];
        CAKeyframeAnimation *an2 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        an2.path = be.CGPath;
        an2.calculationMode = kCAAnimationPaced;
        an2.rotationMode = kCAAnimationRotateAuto;
    //    [self.v.layer addAnimation:an2 forKey:@"an2"];
        
        CAAnimationGroup *group = [CAAnimationGroup animation];
        group.repeatCount = CGFLOAT_MAX;
        group.removedOnCompletion = NO;
        group.fillMode = kCAFillModeForwards;
        group.animations = @[an,an2];
        group.duration = 3.0;
        [self.v.layer addAnimation:group forKey:@"g"];
    
    动画组合

    1.当使用CAAnimationGroup时,单个动画的duration会被group的duration影响,超过的部分不会展示动画
    2.repeatCount,duration,removedOnCompletion,fillMode等这些CAAnimation的属性,如果单个动画没设置,会取group的,但是动画本身的优先级更高
    3.单个动画不会响应代理,group会响应
    4.单个动画的removedOnCompletion也不会生效,取决于group的removedOnCompletion
    5.上面这两个动画,不用group,一起执行,也不会有问题,CAAnimationGroup的重点是定义动画的时间区间

        an.duration = 2.0;
        an.beginTime = .0;
    
        an2.duration = 1.0;
        an2.beginTime = 2.0;
    
    增加了时间区间

    五.CATransition

    CATransition 过渡动画,它作用于整个layer层,使用非常简单,通过设置type和subType来指定动画效果.
    继承自CAAnimation,实例化方法也是+ (instancetype)animation;
    可以使用timingFunction
    同样遵循CAMediaTiming协议

    ViewController2 *vc = ViewController2.new;
        CATransition *transition = [CATransition animation];
        transition.duration = .5f;
        transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        transition.type = @"cube";
        transition.subtype = kCATransitionFromRight;
    //    transition.type = kCATransitionReveal;
    //    transition.subtype = kCATransitionFromLeft;
        [self.navigationController.view.layer addAnimation:transition forKey:nil];
        [self.navigationController pushViewController:vc animated:YES];
    

    这是一段修改push动画的代码,同样使用addAnimation:forKey:添加动画,注意要添加到导航控制器的layer上,
    并且这里的key没有意义,因为CATransition只能使用一次,会被默认设置成kCATransition,这里传nil即可.

    push动画
     _imgv = UIImageView.new;
        _imgv.image = [UIImage imageNamed:@"avatar"];
        _imgv.frame = CGRectMake(100, 100, 200, 200);
        [self.view addSubview:_imgv];
    
    - (void)next{
        CATransition *transition = [CATransition animation];
        transition.duration = .5f;
        transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        transition.type = @"cube";
        transition.subtype = kCATransitionFromRight;
        [self.imgv.layer addAnimation:transition forKey:@"imgv"];
        self.imgv.image = [UIImage imageNamed:@"rocket"];
    }
    
    
    imageView切换内容动画
    - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
    {
        //set up crossfade transition
        CATransition *transition = [CATransition animation];
        transition.type = kCATransitionFade;
        //apply transition to tab bar controller's view
        [self.tabBarController.view.layer addAnimation:transition forKey:nil];
    }
    

    还可以添加在tabBarController: didSelectViewController:来给tabbar切换添加动画

    CATransition 并不作用于指定的图层属性,它作用与整个图层,期间并不清楚哪些图层属性发生了变化,一般来说,只需要将动画添加到被影响图层的superlayer。

    一些CATransition的type:
    pageCurl 向上翻一页
    pageUnCurl 向下翻一页
    rippleEffect 滴水效果
    suckEffect 收缩效果,如一块布被抽走
    cube 立方体效果
    oglFlip 上下翻转效果

    相关文章

      网友评论

          本文标题:Core Animation 四 : CAAnimation

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