iOS核心动画(CoreAnimation)简介

作者: FlyElephant | 来源:发表于2016-04-08 11:17 被阅读339次

    App如果想被大众喜欢,漂亮的UI和精美的动画都是必不可少的,苹果虽然为UIView提供了一些常用动画,但是大部分看起来比较不错的效果都是通过操作Layer层实现的,因此了解核心动画是必要的.CoreAnimation是直接作用在CALayer上的(并非UIView上)非常强大的跨Mac OS X和iOS平台的动画处理API,Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。

    介绍

    先来看一下比较常见的层次图:


    CoreAnimation.png

    核心动画的动画类都是从CAAnimation类继承而来,先来看一下CAAnimation的层次结构:

    CAAnimation.png

    CAAnimation实现了CAMediaTiming协议(提供了动画的持续时间,速度,和重复计)和CAAction协议(为图层触发一个动画动作提供了提供标准化响应)。

    CAPropertyAnimation是CABasicAnimation和CAKeyframeAnimation的抽象父类,CABasicAnimation为图层的属性提供修改,实现起来比较简单;CAKeyframeAnimation支持关键帧动画,你可以指定的图层属性的关键路径动画,包括动画的每个阶段的价值,以及关键帧时间和计时功能的一系列值。

    CAAnimationGroup允许一系列动画效果组合在一起,并行显示动画。

    CATransition提供了一个图层变化的过渡效果,它能影响图层的整个内容。动画进行的时候淡入淡出(fade)、推(push)、显露(reveal)图层的内容。这些过渡效果可以扩展到你自己定制的 Core Image 滤镜。

    动画类同时定义了一个使用贝塞尔曲线来描述动画改变的时间函数。匀速时间函数(lineartiming function)速度会一直保持不变,渐缓时间函数(ease-outtiming function)则在动画接近其生命周期的时候减慢速度。

    CABasicAnimation

    CoreAnimation中最简单的莫过于CABasicAnimation,只需要设置fromValue和toValue即可,先来看一段简单的代码:

    CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotationAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    rotationAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
    rotationAnimation.repeatCount = MAXFLOAT;
    rotationAnimation.duration =10;
    [self.rotationImgView.layer addAnimation:rotationAnimation forKey:@"transform.rotation"];
    

    动画会让图片不断的旋转,效果如下:

    Rotation.gif

    相对应的我们也可以按照X轴和Y轴进行旋转:

    self.rotationXImgView.clipsToBounds=YES;
    self.rotationXImgView.layer.cornerRadius=CGRectGetWidth(self.rotationXImgView.frame)/2;
    
    CABasicAnimation *rotationXAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"];
    rotationXAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    rotationXAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
    rotationXAnimation.repeatCount = MAXFLOAT;
    rotationXAnimation.duration =3;
    [self.rotationXImgView.layer addAnimation:rotationXAnimation forKey:@"transform.rotation.x"];
    
    self.rotationYImgView.clipsToBounds=YES;
    self.rotationYImgView.layer.cornerRadius=CGRectGetWidth(self.rotationYImgView.frame)/2;
    
    CABasicAnimation *rotationYAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
    rotationYAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    rotationYAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
    rotationYAnimation.repeatCount = MAXFLOAT;
    rotationYAnimation.duration =10;
    [self.rotationYImgView.layer addAnimation:rotationYAnimation forKey:@"transform.rotation.y"];
    

    Scale放大效果:

    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 = 0.8;
    [self.scaleImgView.layer addAnimation:scaleAnimation forKey:@"FlyElephant.scale"];
    
    CABasicAnimation *scaleXAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"];
    scaleXAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleXAnimation.toValue = [NSNumber numberWithFloat:1.5];
    scaleXAnimation.autoreverses = YES;//自动反向执行动画效果
    scaleXAnimation.repeatCount = MAXFLOAT;
    scaleXAnimation.duration = 0.8;
    [self.scaleXImgView.layer addAnimation:scaleXAnimation forKey:@"FlyElephant.scale.x"];
    
    CABasicAnimation *scaleYAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"];
    scaleYAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleYAnimation.toValue = [NSNumber numberWithFloat:1.5];
    scaleYAnimation.autoreverses = YES;//自动反向执行动画效果
    scaleYAnimation.repeatCount = MAXFLOAT;
    scaleYAnimation.duration = 0.8;
    [self.scaleYImgView.layer addAnimation:scaleYAnimation forKey:@"FlyElephant.scale.y"];
    
    
    CABasicAnimation *scaleZAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.z"];
    scaleZAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleZAnimation.toValue = [NSNumber numberWithFloat:1.5];
    scaleZAnimation.autoreverses = YES;//自动反向执行动画效果
    scaleZAnimation.repeatCount = MAXFLOAT;
    scaleZAnimation.duration = 0.8;
    [self.scaleZImgView.layer addAnimation:scaleZAnimation forKey:@"FlyElephant.scale.z"];
    

    Translation平移效果

    CABasicAnimation *translationX=[CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
    translationX.toValue=@(200);
    translationX.duration=5;
    translationX.removedOnCompletion=NO;
    translationX.fillMode=kCAFillModeForwards;
    translationX.repeatCount=MAXFLOAT;
    translationX.autoreverses=YES;
    [self.translationXImgView.layer addAnimation:translationX forKey:@"FlyElephant.translation.x"];
    
    CABasicAnimation *translationY=[CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    translationY.toValue=@(100);
    translationY.duration=5;
    translationY.removedOnCompletion=NO;
    translationY.fillMode=kCAFillModeForwards;
    translationY.repeatCount=MAXFLOAT;
    translationY.autoreverses=YES;
    [self.translationYImgView.layer addAnimation:translationY forKey:@"FlyElephant.translation.y"];
    
    
    CABasicAnimation *translation=[CABasicAnimation animationWithKeyPath:@"transform.translation"];
    translation.toValue=[NSValue valueWithCGPoint:CGPointMake(100, 100)];
    translation.duration=5;
    translation.removedOnCompletion=NO;
    translation.fillMode=kCAFillModeForwards;
    translation.repeatCount=MAXFLOAT;
    translation.autoreverses=YES;
    [self.translationImgView.layer addAnimation:translation forKey:@"FlyElephant.translation"];
    

    CABasicAnimation设置比较简单,如果有心的话会有一个疑问,keyPath的里面设置的值是怎么找到的,从里面可以找到所有animationWithKeyPath中的keyPath需要的值呢,最后总结的时候会给出答案,如果有兴趣的可以自己先搜索一番~

    CAKeyframeAnimation

    CAKeyframeAnimation也被称为关键帧动画,因为它可以细化动画在运动过程中的变换的位置,路径以及时间,如果设置的比较好可以完成很多意想不到的效果,本文就简单的稍微设置一下,之后有时间会单独补充一些有意思的动画:

    基于Point的变换

    keyFrame.gif
    CGPoint p1=CGPointMake(self.positionImgView.center.x, self.positionImgView.center.y);
    CGPoint p2=CGPointMake(80, 100);
    CGPoint p3=CGPointMake(100, 120);
    
    CGPoint p4=CGPointMake(120, 150);
    CGPoint p5=CGPointMake(140, 160);
    NSArray *values=[NSArray arrayWithObjects:[NSValue valueWithCGPoint:p1],[NSValue valueWithCGPoint:p2],[NSValue valueWithCGPoint:p3],[NSValue valueWithCGPoint:p4],[NSValue valueWithCGPoint:p5], nil];
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [animation setValues:values];
    [animation setDuration:10.0];
    [animation setCalculationMode:kCAAnimationCubic];
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [self.positionImgView.layer addAnimation:animation forKey:@"FlyElephant.point"];
    

    基于Path变换

    keyFramePath.gif
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path,NULL,self.positionImgView.center.x,self.positionImgView.center.y);
    
    for (NSInteger i=1; i<5; i++) {
        CGPathAddLineToPoint(path, NULL, self.positionImgView.center.x+i*10, self.positionImgView.center.y);
    }
    //曲线
    CGPathAddCurveToPoint(path,NULL,50.0,275.0,150.0,275.0,70.0,120.0);
    CGPathAddCurveToPoint(path,NULL,150.0,275.0,250.0,275.0,90.0,120.0);
    CGPathAddCurveToPoint(path,NULL,250.0,275.0,350.0,275.0,110.0,120.0);
    CGPathAddCurveToPoint(path,NULL,350.0,275.0,450.0,275.0,130.0,120.0);
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [animation setPath:path];
    [animation setDuration:3.0];
    // [animation setAutoreverses:YES];
    CFRelease(path);
    [self.positionImgView.layer addAnimation:animation:@"FlyElephant"];
    

    通过代码我们发现,Path和values接收都是一个数组,而不是一个固定值,这里面我们没有设置keyTimes,下面看一个常见的抖动效果:

    Shake.gif
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.x";
    animation.values = @[ @0, @20, @-20, @20, @0 ];
    animation.keyTimes = @[ @0, @(1 /8.0), @(1/ 2.0), @(7/ 8.0), @1 ];
    animation.duration =0.5;
    animation.additive = YES;
    [self.textField.layer addAnimation:animation forKey:@"FlyElephant.Shake"];
    

    CAAnimationGroup

    CAAnimationGroup被称为动画组,动画组可以将各种不同的动画同时执行,如果你想,你就可以设置千变万化的效果,下面简单的将CABasicAnimation和CAKeyframeAnimation结合在一起做一个简单的动画效果:

    Group.gif
    CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAnimation.fromValue = [NSNumber numberWithFloat:1.0];
    scaleAnimation.toValue = [NSNumber numberWithFloat:2.0];
    NSMutableArray *arr=[NSMutableArray array];
    for (NSInteger i=0; i<5; i++) {
         CGPoint p=CGPointMake(self.groupImgView.center.x+i*20, self.groupImgView.center.y+i*20);
        [arr addObject:[NSValue valueWithCGPoint:p]];
    }
    NSArray *values=arr;
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [animation setValues:values];
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    
    CAAnimationGroup *animationGroup=[CAAnimationGroup animation];
    animationGroup.animations=@[scaleAnimation,animation];
    animationGroup.duration=5.0f;
    animationGroup.autoreverses=YES;
    [self.groupImgView.layer addAnimation:animationGroup forKey:@"FlyElephant.AnimationGroup"];
    

    这个算是基本动画,需求不一样,设置的效果就不一样~

    AnimationWithKeyPath的值

    最开始做动画一般都会对keyPath这个值莫名其妙,因为它不是常量,需要变换的时候找不到对应的需要设置的值,如果你在网上搜索,很可能看到的是这张图:

    Snip20160408_1.png

    下面这张图你基本上是找不到的,如下:

    Snip20160408_2.png

    这两张图涵盖所有你需要设置的keypath,两张图都是截取自苹果官网,自己当时找的时候也发费了一番功夫,参考链接如下:
    https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html#//apple_ref/doc/uid/TP40004514-CH11-SW2
    https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Key-ValueCodingExtensions/Key-ValueCodingExtensions.html#//apple_ref/doc/uid/TP40004514-CH12-SW2

    Swift 抖动效果
    <pre><code>let animation:CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") animation.fromValue = 0.1 animation.toValue = -0.1 animation.duration = 0.1; animation.autoreverses = true; //是否重复 animation.repeatCount = 2; animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) self.shakeView.layer.add(animation, forKey: "shake")</code></pre>

    相关文章

      网友评论

        本文标题:iOS核心动画(CoreAnimation)简介

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