美文网首页
Core Animation

Core Animation

作者: 蔚尼 | 来源:发表于2018-06-27 18:03 被阅读21次

    一.简介

    • Core Animation:核心动画。可以用在iOS和Mac OS X平台。
    • Core Animation动画都是在后台操作的,不会阻塞主线程;
    • Core Animation是直接作用在CALayer上的,非UIView。
    核心动画继承结构

    核心动画使用步骤:

    1.先要有CALayer
    2.初始化弍CAAnimation对象,并设置动画相关属性
    3.增加CAAnimation到CALayer中

    常用属性

    1.duration : 动画的持续时间
    2.beginTime : 动画的开始时间
    3.repeatCount : 动画的重复次数
    4.autoreverses : 执行的动画按照原动画返回执行
    5.timingFunction : 控制动画的显示节奏系统提供五种值选择,分别是

    kCAMediaTimingFunctionLinear 线性动画
    kCAMediaTimingFunctionEaseIn 先快后慢
    kCAMediaTimingFunctionEaseOut 先慢后快
    kCAMediaTimingFunctionEaseInEaseOut 先慢后快再慢
    kCAMediaTimingFunctionDefault 默认,也属于中间比较快
    

    6.delegate : 动画代理。能够检测动画的执行和结束。

    @interface NSObject (CAAnimationDelegate)
     - (void)animationDidStart:(CAAnimation *)anim;
     - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
    @end
    

    7.path:关键帧动画中的执行路径
    8.type:过渡动画的动画类型,系统提供了四种过渡动画。

    kCATransitionFade 渐变效果
    kCATransitionMoveIn 进入覆盖效果
    kCATransitionPush 推出效果
    kCATransitionReveal 揭露离开效果
    subtype : 过渡动画的动画方向
    kCATransitionFromRight 从右侧进入
    kCATransitionFromLeft 从左侧进入
    kCATransitionFromTop 从顶部进入
    kCATransitionFromBottom 从底部进入
    

    9.removedOnCompletion:动画完成时会自动删除动画,让不让动画被删除
    10.fillMod:设置动画完成保持什么状态(默认回到原位)

    二.iOS动画的调用方式

    第一种:UIView 代码块调用

    _demoView.frame = CGRectMake(0, SCREEN_HEIGHT/2-50, 50, 50);
    [UIView animateWithDuration:1.0f animations:^{
    _demoView.frame = CGRectMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50, 50, 50);
    } completion:^(BOOL finished) {
    _demoView.frame = CGRectMake(SCREEN_WIDTH/2-25, SCREEN_HEIGHT/2-50, 50, 50);
    }];
    

    第二种:UIView [begin commit]模式

    _demoView.frame = CGRectMake(0, SCREEN_HEIGHT/2-50, 50, 50);
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.0f];
    _demoView.frame = CGRectMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50, 50, 50);
    [UIView commitAnimations];
    

    第三种:使用Core Animation中的类

    CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"position"];
    anima.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, SCREEN_HEIGHT/2-75)];
    anima.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-75)];
    anima.duration = 1.0f;
    [_demoView.layer addAnimation:anima forKey:@"positionAnimation"];
    

    三.Core Animation的使用

    1. 基础动画/CABasicAnimation

    重要属性

    fromValue:keyPath对应的初始值
    toValue:keyPath对应的结束值

    所有的旋转,缩放都是绕着锚点进行;
    基础动画主要提供了对于CALayer对象中的可变属性进行简单动画的操作。比如:
    位移:position
    透明度:opacity
    缩放:transform.scale
    旋转:transform.rotation.z
    背景色:backgroundColor
    ...

    1.1位移

    其他操作也是更改keyPath和formValue,toValue即可;formValue不写则默认是动画之前的值。

        //1.创建动画对象
        CABasicAnimation * anim = [CABasicAnimation animation];
        //2.设置动画属性
        anim.keyPath = @"position.y";
        anim.toValue = @(400);
    
        //动画完成时会自动删除动画,让动画不要被删除
        anim.removedOnCompletion = NO;
        //设置动画完成保持什么状态(默认回到原位)
        anim.fillMode = kCAFillModeForwards;
    
        [self.redView.layer addAnimation:anim forKey:@"anim1"];
    
    
    基础动画.gif

    1.2透明度

    /**
     *  透明度动画
     */
    -(void)opacityAniamtion{
        CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"opacity"];
        anima.fromValue = [NSNumber numberWithFloat:1.0f];
        anima.toValue = [NSNumber numberWithFloat:0.2f];
        anima.duration = 1.0f;
        [_demoView.layer addAnimation:anima forKey:@"opacityAniamtion"];
    }
    

    1.3缩放动画

    /**
     *  缩放动画
     */
    -(void)scaleAnimation{
        CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"transform.scale"];//同上
        anima.toValue = [NSNumber numberWithFloat:2.0f];
        anima.duration = 1.0f;
        [_demoView.layer addAnimation:anima forKey:@"scaleAnimation"];
        
    }
    

    1.4旋转动画

    /**
     *  旋转动画
     */
    -(void)rotateAnimation{
        CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];//绕着z轴为矢量,进行旋转(@"transform.rotation.z"==@@"transform.rotation")
        anima.toValue = [NSNumber numberWithFloat:M_PI];
        anima.duration = 1.0f;
        [_demoView.layer addAnimation:anima forKey:@"rotateAnimation"];
        
    }
    

    1.5背景色变化动画

    /**
     *  背景色变化动画
     */
    -(void)backgroundAnimation{
        CABasicAnimation *anima = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
        anima.toValue =(id) [UIColor greenColor].CGColor;
        anima.duration = 1.0f;
        [_demoView.layer addAnimation:anima forKey:@"backgroundAnimation"];
    }
    

    2. 关键帧动画/CAKeyframeAnimation

    CAKeyframeAnimation和CABaseAnimation都属于CAPropertyAnimatin的子类。CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。

    重要属性

    values:NSArray类型。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧。

    path:可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的position和anchorPosition有用。如果你设置了path,那么values将被忽略。

    keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的。

    2.1关键帧动画-values使用

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
            
        //帧动画(进行多个值之间的转换;可以根据路径做动画)
        CAKeyframeAnimation * anim = [CAKeyframeAnimation animation];
        anim.keyPath = @"transform.rotation";
        anim.values = @[@angleToRadio(-5),@angleToRadio(5),@angleToRadio(-5)];//从-5度旋转到5度,再到-5度
    
        anim.repeatCount = MAXFLOAT;
        anim.autoreverses = YES;//自动翻转
        anim.duration = 0.1;
        
        [self.imageView.layer addAnimation:anim forKey:@"anmi"];
        
    }
    
    抖动.gif

    2.1关键帧动画-路径使用

        //添加帧动画
        CAKeyframeAnimation * fishAni = [CAKeyframeAnimation animation];
        fishAni.keyPath = @"position";
        
        UIBezierPath * fishPath = [UIBezierPath bezierPath];
        [fishPath moveToPoint:CGPointMake(50, 200)];
        [fishPath addLineToPoint:CGPointMake(50, 100)];
        [fishPath addLineToPoint:CGPointMake(100, 100)];
        [fishPath addLineToPoint:CGPointMake(50, 200)];
        
        fishAni.path = fishPath.CGPath;
        fishAni.duration = 5;
        fishAni.repeatCount = HUGE;
            
        [self.fishLayer addAnimation:fishAni forKey:@"fishAni"];
        
    
    路径动画.gif

    3. 过渡动画/CATransition

    重要属性

    • type:
      转场动画类型,fade、moveIn、push、reveal;
      私有API提供了其他很多非常炫的过渡动画,比如@"cube"、@"suckEffect"、@"oglFlip"、 @"rippleEffect"、@"pageCurl"、@"pageUnCurl"、@"cameraIrisHollowOpen"、@"cameraIrisHollowClose"等。不建议开发者们使用。因为苹果公司不提供维护,并且有可能造成你的app审核不通过。

    • subtype:转场方向

    • startProgress:从哪个位置开始动画

    • endProgress:从哪个位置结束动画

    注意:转场代码和转场动画必须在同一个方法当中

    static int _imageIndex = 0;
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        ///转场代码和转场动画必须在同一个方法当中
        //1.转场代码
        _imageIndex++;
        if (_imageIndex == 6) {
            _imageIndex = 0;
        }
        NSString * imageName = [NSString stringWithFormat:@"%d",_imageIndex];
        self.imageView.image = [UIImage imageNamed:imageName];
        
        //2.转场动画
        //添加动画
        CATransition * anim = [CATransition animation];
        //转场动画
        anim.type = @"cube";
        //转场方向
        anim.subtype = @"fromLeft";
        //从哪个位置开始动画
        anim.startProgress = 0.2;
        anim.endProgress = 0.5;
        anim.duration = 1.0;
        [self.imageView.layer addAnimation:anim forKey:@"anim"];
    }
    
    转场动画.gif

    4. 动画组/CAAnimationGroup

    动画组顾名思义,就把一组动画一起添加到layer上面;

    重要属性

    animations: 用来保存一组动画对象的NSArray

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        //位移动画
        CABasicAnimation * anim = [CABasicAnimation animation];
        anim.keyPath = @"position.y";
        anim.toValue = @400;
    //    anim.duration = 1.0;
    //    anim.removedOnCompletion = NO;
    //    anim.fillMode = kCAFillModeForwards;
    //    [self.redView.layer addAnimation:anim forKey:@"anim"];
        
        //缩小动画
        CABasicAnimation * anim2 = [CABasicAnimation animation];
        anim2.keyPath = @"transform.scale";
        anim2.toValue = @0.5;
    //    anim2.duration = 1.0;
    //    anim2.removedOnCompletion = NO;
    //    anim2.fillMode = kCAFillModeForwards;
    //    [self.redView.layer addAnimation:anim2 forKey:@"anim2"];
    
        CAAnimationGroup * groupAnim = [CAAnimationGroup animation];
        groupAnim.animations = @[anim,anim2];
        //把数组当中的所有动画都添加到layer上面
        groupAnim.duration = 1.0;
        groupAnim.removedOnCompletion = NO;
        groupAnim.fillMode = kCAFillModeForwards;
        [self.redView.layer addAnimation:groupAnim forKey:nil];
        
    }
    
    
    动画组.gif

    5. 粒子动画

    • CAEmitterLayer:主要控制发射源的位置、尺寸、发射模式、发射源的形状等等;
    • CAEmitterCell:可以看作是单个粒子的原型(例如一个雪花),可设置属性来控制粒子的图片,颜色,方向,运动,缩放比例和生命周期。
    粒子效果.gif
        //1、layer
        CAEmitterLayer * emitterLayer = [CAEmitterLayer layer];
        //粒子发射的位置
        emitterLayer.emitterPosition = CGPointMake(120, 20);
        //发射源尺寸大小
        emitterLayer.emitterSize = CGSizeMake(20, 20);
        
        //发射模式
        emitterLayer.emitterMode = @"surface";
        //发射形状
        emitterLayer.emitterShape = @"line";
        
        //2、cell
        //创建粒子
        CAEmitterCell * cell = [CAEmitterCell emitterCell];
        //粒子的名字
        cell.name = @"snow";
        //粒子参数的速度乘数因子
        cell.birthRate = 1.0;
        cell.lifetime = 120.0;
        //粒子速度
        cell.velocity = 10.0;
        //粒子的速度范围
        cell.velocityRange = 10;
        //粒子y方向的加速度分量
        cell.yAcceleration = 2;
        //周围发射角度
        cell.emissionRange = 0.5 * M_PI;
        
        //设置粒子图片
        cell.contents = (id)[UIImage imageNamed:@"DazFlake"].CGImage;
        
        emitterLayer.emitterCells = @[cell];
        
        [self.view.layer insertSublayer:emitterLayer atIndex:0];
    

    更多属性解释可查看:iOS动画开发----粒子系统---彩带效果
    iOS 粒子效果

    6. 复制/CAReplicatorLayer

    效果

    需要使用CAReplicatorLayer达到上图效果;相当于把上面的图片复制一份并旋转。
    1、先在view上面添加一个imageView;view的layer层是CALayer类型,我们需要修改为CAReplicatorLayer类型。

    添加图片到view上面
    @implementation VCView
    
    //返回当前view内部layer的类型
    +(Class)layerClass{
        
        //要复制图层,要把所在的图层修改为复制层CAReplicatorLayer才可以进行复制
        //原本是calyer类型,现在修改为CAReplicatorLayer类型
        return [CAReplicatorLayer class];
    }
    
    @end
    

    2、view所在的controller里面,获取view的layer层,并进行复制。

    复制是围绕着layer层的锚点进行复制的;

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        NSLog(@"%@",self.view.layer);
            
        CAReplicatorLayer * repLayer = (CAReplicatorLayer *)self.view.layer;
        //设置复制2份
        repLayer.instanceCount = 2;
       //绕着复制层的锚点进行旋转,即绕着view的layer层锚点进行旋转
        repLayer.instanceTransform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
        
        //修改复制出来的颜色通道,每个色度-1,达到灰色效果
        repLayer.instanceRedOffset -=0.1;
        repLayer.instanceGreenOffset -=0.1;
        repLayer.instanceBlueOffset -=0.1;
        repLayer.instanceAlphaOffset -=0.1;
    
    }
    
    
    

    7. 综合效果

    效果

    绘制以上效果:
    1.触摸view的时候记录上这些点,把这些点绘制到路径上;
    2.点击开始绘制按钮,把红色的layer使用帧动画沿着路径运动;
    3.使用CAReplicatorLayer复制多个红色layer,一个个的沿着路径运动;

    #import "VCView.h"
    
    @interface VCView ()
    
    @property(nonatomic,strong)UIBezierPath * path;
    
    @property(nonatomic,strong)CALayer * aniLayer;
    
    @end
    @implementation VCView
    
    -(void)awakeFromNib{
        
        [super awakeFromNib];
        
        //给view添加手势
        UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
        [self addGestureRecognizer:pan];
        
        //创建路径
        UIBezierPath * path = [UIBezierPath bezierPath];
        self.path = path;
    
    }
    //1、根据手势创建路径
    -(void)pan:(UIPanGestureRecognizer *)pan{
        
        //获取当前的点
        CGPoint currentP = [pan locationInView:self];
        if (pan.state == UIGestureRecognizerStateBegan) {
        
            //设置起点
            [self.path moveToPoint:currentP];
        
        }else if(pan.state == UIGestureRecognizerStateChanged){
            
            //添加一根线到当前点
            [self.path addLineToPoint:currentP];
            
            //重回(会调用drawRect)
            [self setNeedsDisplay];
        }
        
    }
    -(void)drawRect:(CGRect)rect{
        
        //绘制
        [self.path stroke];
        
    }
    //2、把红色的layer使用帧动画沿着路径运动
    //3、使用CAReplicatorLayer复制多个红色layer,一个个的沿着路径运动;
    - (IBAction)beginAnimation:(id)sender {
        
        CALayer * aniLayer = [CALayer layer];
        aniLayer.backgroundColor = [UIColor redColor].CGColor;
        aniLayer.frame = CGRectMake(0, 0, 10, 10);
        [self.layer addSublayer:aniLayer];
        _aniLayer = aniLayer;
        
        CAKeyframeAnimation * keyAnim = [CAKeyframeAnimation animation];
        keyAnim.path = self.path.CGPath;
        keyAnim.keyPath = @"position";
        keyAnim.duration = 3;
        keyAnim.repeatCount = 3;
        [_aniLayer addAnimation:keyAnim forKey:nil];
    
        CAReplicatorLayer * repl = (CAReplicatorLayer *)self.layer;
        repl.instanceCount = 3;
        repl.instanceDelay = 0.1;
        
    }
    
    +(Class)layerClass{
        
        return [CAReplicatorLayer class];
    }
    
    
    - (IBAction)endAnimation:(id)sender {
        
        UIBezierPath * path = [UIBezierPath bezierPath];
        self.path = path;
        [self setNeedsDisplay];
        
        [_aniLayer removeFromSuperlayer];
        _aniLayer = nil;
    }
    
    
    

    8. 检索一个动画

    - (CAAnimation *)animationForKey:(NSString *)key;
    

    不支持在动画运行过程中修改动画,所以这个方法主要用来检测动画的属性,或者判断它是否被添加到当前图层中。

    9. 在动画过程中取消动画

    为了终止一个指定的动画,你可以用如下方法把它从图层移除掉:

    - (void)removeAnimationForKey:(NSString *)key;
    

    或者移除所有动画:

    - (void)removeAllAnimations;
    

    一般说来,动画在结束之后被自动移除,除非设置removedOnCompletion为NO,如果你设置动画在结束之后不被自动移除,那么当它不需要的时候你要手动移除它;否则它会一直存在于内存中,直到图层被销毁。

    UIView与核心动画的区别?
    1.核心动画只作用在layer上面;
    2.核心动画看到的一切都是假象,并没有修改属性的真实值;(比如UIImageView的layer进行了移动,但是UIImgeView的位置没有变)

    什么时候使用核心动画,什么时候使用UIView动画?
    当需要与用户交互时,必须使用UIView动画;
    当根据路径做动画时,使用核心动画(核心动画里面的帧动画)
    做转场动画时,使用核心动画,转场类型比较多;

    参考:
    iOS动画(Core Animation)总结

    iOS核心动画高级技巧

    相关文章

      网友评论

          本文标题:Core Animation

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