IOS CoreAnimation 核心动画解析

本文介绍了IOS中的CoreAnimation核心动画,通过代码示例展示了如何使用UIView动画API,包括转场动画、Spring动画和帧动画。并探讨了更复杂的CoreAnimation,如CADisplayLink、CALayer的子类CAShaperLayer、CATextLayer和CAGradientLayer的使用,以及如何绘制图形、文字和渐变色。最后,讨论了如何结合这些技术实现更复杂动画效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        如果我们开发的需求不是很特殊,IOS给我们提供的UI层的动画API就够我们开发用的了,比如UIView.animationWithDuration,UIView.transationFromView,

UIView.animateKeyFramesWithDuration,然后在利用工具类CFAffineTransFormXX就得实现我们比较常见的动画了,

一下是各种动画的练习


- (IBAction)commAnimation:(id)sender {

//最原始的原始动画

    [UIViewbeginAnimations:@"Common"context:nil];

    [UIViewsetAnimationDelay:1];

    [UIViewsetAnimationDuration:1.0];

    [UIViewsetAnimationDelegate:self];

    [UIViewsetAnimationRepeatCount:2];

    [UIViewsetAnimationWillStartSelector:@selector(startAni:)];

    [UIViewsetAnimationDidStopSelector:@selector(stopAni:)];

    [UIViewsetAnimationCurve:UIViewAnimationCurveEaseOut];

    //  self.mImagView.frame=self.mTextView.frame;更改中心就是移动

    //      self.mImagView.bounds=self.view.bounds; 更改bounds

    // self.mImagView.backgroundColor=[UIColor redColor];更改背景颜色

    [UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.mImagView cache:YES];//旋转或者翻页效果动画

    

    [UIViewcommitAnimations];


    //转场动画fromView要消失的 toView是要进入视图的

    

    [UIView transitionFromView:_mTextView toView:_mImagView duration:2 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationTransitionCurlDown completion:nil];

}

- (IBAction)blockAnimation:(id)sender {

    //IOS7.0以后加入的Spring动画支持

    [UIViewanimateWithDuration:2.0fdelay:0.5fusingSpringWithDamping:0.5initialSpringVelocity:0.25options:UIViewAnimationOptionCurveEaseOutanimations:^{

        CGFloat orX=self.mTextView.center.x;

        CGFloat orY=self.mTextView.center.y;

        [self.mTextView setCenter:CGPointMake(orX+100, orY+100)];

        

        self.mLable.alpha=0.25;

        self.mImagView.transform=CGAffineTransformScale(self.mImagView.transform,0.5,0.5);

        

    } completion:^(BOOL finished) {

        NSLog(@"第一个动画完毕");

    } ];

}

//帧动画对于普通的动画来说也算是复杂的了

- (IBAction)framesAnimation:(id)sender {

        self.mImagView.image=nil;

        [UIView animateKeyframesWithDuration:9.0 delay:0.f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{

           [UIView addKeyframeWithRelativeStartTime:0.f relativeDuration:1.0/4 animations:^{

                self.mImagView.backgroundColor=[UIColor colorWithRed:0.9475 green:0.1921 blue:0.1746 alpha:1.0];

            }];

            [UIView addKeyframeWithRelativeStartTime:1.0/4 relativeDuration:1.0/4 animations:^{

                self.mImagView.backgroundColor=[UIColor colorWithRed:0.1064 green:0.6052 blue:0.0334 alpha:1.0];

           }];

           [UIView addKeyframeWithRelativeStartTime:2.0/4 relativeDuration:1.0/4 animations:^{

               self.mImagView.backgroundColor=[UIColor colorWithRed:0.1366 green:0.3017 blue:0.8411 alpha:1.0];

           }];

           [UIView addKeyframeWithRelativeStartTime:3.0/4 relativeDuration:1.0/4 animations:^{

               self.mImagView.backgroundColor=[UIColor colorWithRed:0.619 green:0.037 blue:0.6719 alpha:1.0];

            }];

        }completion:^(BOOL finished){

            NSLog(@"动画结束");

       }];

    CGFloat orX=self.mLable.center.x;

    CGFloat orY=self.mLable.center.y;

    CGPoint orCenter=self.mLable.center;

    [UIViewanimateKeyframesWithDuration:2delay:0.5options:UIViewKeyframeAnimationOptionRepeatanimations:^{

        

        [UIViewaddKeyframeWithRelativeStartTime:0.0relativeDuration:0.25animations:^{

            [self.mLable setCenter:CGPointMake(orX+80, orY-20)];

        }];

        

        [UIViewaddKeyframeWithRelativeStartTime:0.15relativeDuration:0.4animations:^{

            self.mLable.transform=CGAffineTransformMakeRotation(-M_PI_4/2);

        }];

        

        [UIViewaddKeyframeWithRelativeStartTime:0.25relativeDuration:0.35animations:^{

            [self.mLable setCenter:CGPointMake(orX+100, orY-50)];

            self.mLable.alpha=0;

        }];

        

        [UIViewaddKeyframeWithRelativeStartTime:0.55relativeDuration:0.05animations:^{

            self.mLable.transform=CGAffineTransformIdentity;

            [self.mLable setCenter:CGPointMake(0, orY)];

        }];

        [UIViewaddKeyframeWithRelativeStartTime:0.65relativeDuration:0.5animations:^{

            self.mLable.alpha=1.0;

            self.mLable.center=orCenter;

        }];

        

    } completion:^(BOOL finished) {

        

    }];  

}


   但是如果我们要想实现比较复杂的动画还是必须要了解和学习IOS CoreAnimation的。

其实我们动画刷新UI使用的CADisplayLink,其实他是一个专门用来刷新UI的 NSTimer使用起来比较简单,

-(void)useCADisplayLink{

    

    CADisplayLink *cADisplayLink=[CADisplayLinkdisplayLinkWithTarget:selfselector:@selector(timerDoSelector)];

    [cADisplayLink addToRunLoop:[NSRunLoopcurrentRunLoop]forMode:UITrackingRunLoopMode];//这样selector就会重复的周期性执行了

    //停止执行

    [cADisplayLink invalidate];

    cADisplayLink=nil; 


}

这里用到了NSRunLoop,其实RunLoop在IOS中作用非常之大,如果没有它,你看到的IOS APP页面将是一潭死水一般,它依附于一个线程,然后一直轮训着,除了主线程及UI线程外,我们自己创建的各种线程,如果想用RunLoop必须自己创建,RunLoop也需要在特定的RunModes下执行,而且可以在RunModes间进行灵活切换,IOS系统目前有5种RunModes,我们比较常用的就是默认的NSDefaultRunLoopMode和UITrackingRunLoopMode,还有一个不是5个之中但是也很重要,它是前面提到的俩Mode的占位符号,有俩它就相当于前面的俩,就是NSRunLoopCommonMode。


前面只是个小插曲,其实IOS核心动画的关键类是CALayer,它是专门解决绘图的,它有N个子类,分别有着自己特出的作用,本篇文章着重用来介绍它的三个子类:

  1:CAShaperLayer  2:CATextLayer  3:CAGradientLayer

CAShaperLayer:从名字我们就可以看到,他是用来绘制各种图形界面的,直线,曲线,圆形,不规则形状等:

      

//具体实例代码如下

-(void) testCALayers{

    CAShapeLayer *shapeLayer=[CAShapeLayerlayer];

    shapeLayer.lineWidth=3;

    shapeLayer.strokeColor=[UIColorblueColor].CGColor;

    UIBezierPath *bezierPath=[UIBezierPathbezierPathWithRect:CGRectMake(100,200,200,200)];//正方形

    UIBezierPath *pathRoundRect=[UIBezierPathbezierPathWithRoundedRect:CGRectMake(100,200,200,200)cornerRadius:5];//倒角方形

    UIBezierPath *ciclePath=[UIBezierPathbezierPathWithOvalInRect:CGRectMake(100,100,200,100)];

    shapeLayer.path=ciclePath.CGPath;//这样会有默认的黑色填充色,正方形里面都是黑色

    shapeLayer.fillColor=[UIColorclearColor].CGColor;//设置自己想要的内部填充色

    

    [self.view.layeraddSublayer:shapeLayer];

    

    CAShapeLayer *shaperLayer1=[CAShapeLayerlayer];

    shaperLayer1.lineWidth=2;

    shaperLayer1.strokeColor=[UIColorredColor].CGColor;

    shaperLayer1.fillColor=[UIColorblueColor].CGColor;

    //左上角和右下角倒角的长方形,倒角半径是50

    UIBezierPath *roundPath=[UIBezierPathbezierPathWithRoundedRect:CGRectMake(100,220,200,100)byRoundingCorners:UIRectCornerTopLeft|UIRectCornerBottomRightcornerRadii:CGSizeMake(50,50)];

    shaperLayer1.path=roundPath.CGPath;

    [self.view.layeraddSublayer:shaperLayer1];

    

    CAShapeLayer *shaperLayer2=[CAShapeLayerlayer];

    shaperLayer2.lineWidth=2;

    shaperLayer2.strokeColor=[UIColoryellowColor].CGColor;

    shaperLayer2.fillColor=[UIColorredColor].CGColor;

    //分别表示圆点圆弧半径圆弧起点和终点是否是顺时针方向链接起点和终点

    UIBezierPath *pathArc=[UIBezierPathbezierPathWithArcCenter:CGPointMake(200,390)radius:50startAngle:0endAngle:M_PI+M_PI_2clockwise:YES];

    shaperLayer2.path=pathArc.CGPath;

    [self.view.layeraddSublayer:shaperLayer2];

    

    //画线

    CAShapeLayer *shapeLayer3=[CAShapeLayerlayer];

    shapeLayer3.lineWidth=2;

    shapeLayer3.strokeColor=[UIColorgreenColor].CGColor;

    

    UIBezierPath *linePath=[UIBezierPathbezierPath];

    

    //把画笔起点移动到CGPointMake(100, 500)

    [linePath moveToPoint:CGPointMake(100,500)];

    

    [linePath addLineToPoint:CGPointMake(110,490)];

    [linePath addLineToPoint:CGPointMake(120,480)];

    [linePath addLineToPoint:CGPointMake(130,450)];

    [linePath addLineToPoint:CGPointMake(150,410)];

    [linePath addLineToPoint:CGPointMake(170,450)];

    [linePath addLineToPoint:CGPointMake(190,420)];

    [linePath addLineToPoint:CGPointMake(220,450)];

    shapeLayer3.path=linePath.CGPath;

    [self.view.layeraddSublayer:shapeLayer3];

    

}

//正统的UIBezierPath曲线


-(void)testBezierPath{

    CAShapeLayer *layer1=[CAShapeLayerlayer];

    layer1.lineWidth=3;

    layer1.strokeColor=[UIColorbrownColor].CGColor;

    layer1.fillColor=[UIColorclearColor].CGColor;

    

    UIBezierPath *circlePath=[UIBezierPathbezierPathWithOvalInRect:CGRectMake(100,100, 200,200)];

    

    //构造一个子路径

    UIBezierPath *sonPath=[UIBezierPathbezierPath];

    [sonPath moveToPoint:CGPointMake(100,200)];

    [sonPath addLineToPoint:CGPointMake(300,200)];

    

    //把字Path添加到父Path

    [circlePath appendPath:sonPath];

    

    //再创建个子路径

    

    UIBezierPath *son1=[UIBezierPathbezierPath];

    [son1 moveToPoint:CGPointMake(200,100)];

    [son1 addLineToPoint:CGPointMake(200,300)];

    

     //把字Path添加到父Path

    [circlePath appendPath:son1];

    

    layer1.path=circlePath.CGPath;

    

    [self.view.layeraddSublayer:layer1];

    

    //直接利用一个Path拼接图形

    

    CAShapeLayer *layer2=[CAShapeLayerlayer];

    

    layer2.lineWidth=3;

    layer2.strokeColor=[UIColorblueColor].CGColor;

    layer2.fillColor=[UIColorclearColor].CGColor;

    

    UIBezierPath *bezier=[UIBezierPathbezierPath];

    

    //先画一个90度的圆弧

    

    [bezier addArcWithCenter:CGPointMake(200,400) radius:50startAngle:0endAngle:M_PI_2clockwise:YES];

    

    //在拼接一条直线

    [bezier addLineToPoint:CGPointMake(150,350)];

    

    layer2.path=bezier.CGPath;

    [self.view.layeraddSublayer:layer2];

    

    //画一条真正的贝塞尔曲线

    CAShapeLayer *shaper3=[CAShapeLayerlayer];

    shaper3.lineWidth=3;

    shaper3.strokeColor=[UIColoryellowColor].CGColor;

    

    UIBezierPath *bezier2=[UIBezierPathbezierPath];

    

    [bezier2 moveToPoint:CGPointMake(100,400)];

    [bezier2 addCurveToPoint:CGPointMake(200,500) controlPoint1:CGPointMake(50,460) controlPoint2:CGPointMake(200,420)];

    shaper3.path=bezier2.CGPath;

    //贝塞尔曲线的起点是(100, 400)中间两个平滑拐弯点分别是(50, 460)(200, 420)

    

    [self.view.layeraddSublayer:shaper3];

    

 

}



CATextLayer:是用来绘制文字的


//实例代码如下

    //CATextLayer画文字

    

    CATextLayer *textLayer=[CATextLayer layer];

    textLayer.foregroundColor=[UIColor blueColor].CGColor;

    textLayer.alignmentMode=kCAAlignmentJustified;

    textLayer.wrapped=YES;

    textLayer.frame=CGRectMake(150400400500);

    UIFont *font=[UIFont systemFontOfSize:11];

    CFStringRef fontName=(__bridge CFStringRef)font.fontName;

    CGFontRef fontRef =CGFontCreateWithFontName(fontName);

    textLayer.font = fontRef;

    textLayer.fontSize = font.pointSize;

    CGFontRelease(fontRef);

    textLayer.string=@"hello just for test";

    textLayer.contentsScale=[UIScreen mainScreen].scale;//加上这一行字体会清晰好多

    [self.view.layer addSublayer:textLayer];

    //    [shaperLayer2 setMask:textLayer];



CAGradientLayer:是用来绘制渐变色的

         IOS View的Layer的坐标系统如下图



代码实例:


   

    CAGradientLayer *gradientLayer=[CAGradientLayer layer];

    gradientLayer.frame=CGRectMake(100, 520, 200, 100);

    

    gradientLayer.colors=[NSArray arrayWithObjects:[UIColor redColor].CGColor,

                          [UIColor blueColor].CGColor,[UIColor yellowColor].CGColor,

                          [UIColor redColor].CGColor,

                          [UIColor blueColor].CGColor,[UIColor yellowColor].CGColor,nil];

    gradientLayer.locations=[NSArray arrayWithObjects:[NSNumber numberWithFloat:0],

                             [NSNumber numberWithFloat:0.15],[NSNumber numberWithFloat:0.3],

                             [NSNumber numberWithFloat:0.45],[NSNumber numberWithFloat:0.6],

                             [NSNumber numberWithFloat:0.8],[NSNumber numberWithFloat:1],nil];

    gradientLayer.startPoint=CGPointMake(0, 0);

    gradientLayer.endPoint=CGPointMake(1, 1);

    [self.view.layer addSublayer:gradientLayer];


注:colorLayer.colors是渐变的颜色的数组,colorLayer.locations是每个颜色开始渐变的位置


也可以实现复杂点动画效果:


@interface RootViewController ()

@property (nonatomic, strong) GCDTimer  *timer;

@end

@implementation RootViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    CAGradientLayer *colorLayer = [CAGradientLayer layer];
    colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    colorLayer.frame    = (CGRect){CGPointZero, CGSizeMake(200, 200)};
    colorLayer.position = self.view.center;
    [self.view.layer addSublayer:colorLayer];

    // 颜色分配
    colorLayer.colors = @[(__bridge id)[UIColor cyanColor].CGColor,
                          (__bridge id)[UIColor orangeColor].CGColor,
                          (__bridge id)[UIColor magentaColor].CGColor];
    
    // 起始点
    colorLayer.startPoint = CGPointMake(0, 0);
    
    // 结束点
    colorLayer.endPoint   = CGPointMake(1, 0);
    
    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
    [_timer event:^{
        
        static CGFloat test = - 0.1f;
        
        if (test >= 1.1)
        {
            test = - 0.1f;
            [CATransaction setDisableActions:YES];
            colorLayer.locations  = @[@(test), @(test + 0.05), @(test + 0.1)];
        }
        else
        {
            [CATransaction setDisableActions:NO];
            colorLayer.locations  = @[@(test), @(test + 0.05), @(test + 0.1)];
        }
        
        test += 0.1f;
        
    } timeInterval:NSEC_PER_SEC];
    [_timer start];
}

@end
复制代码

复制代码
    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
    [_timer event:^{
        
        static CGFloat test = - 0.1f;
        
        if (test >= 1.1)
        {
            test = - 0.1f;
            [CATransaction setDisableActions:NO];
            colorLayer.locations  = @[@(test), @(test + 0.01), @(test + 0.011)];
        }
        else
        {
            [CATransaction setDisableActions:NO];
            colorLayer.locations  = @[@(test), @(test + 0.01), @(test + 0.011)];
        }
        
        test += 0.1f;
        
    } timeInterval:NSEC_PER_SEC];
    [_timer start];
复制代码

配合CAShapeLayer使用

复制代码
//
//  RootViewController.m
//
//  Copyright (c) 2014年 Y.X. All rights reserved.
//

#import "RootViewController.h"
#import "YXGCD.h"

@interface RootViewController ()

@property (nonatomic, strong) GCDTimer  *timer;

@end

// 将常数转换为度数
#define   DEGREES(degrees)  ((M_PI * (degrees))/ 180.f)

@implementation RootViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];

    CAGradientLayer *colorLayer = [CAGradientLayer layer];
    colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    colorLayer.frame    = (CGRect){CGPointZero, CGSizeMake(200, 200)};
    colorLayer.position = self.view.center;
    [self.view.layer addSublayer:colorLayer];

    // 颜色分配
    colorLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,
                          (__bridge id)[UIColor whiteColor].CGColor,
                          (__bridge id)[UIColor redColor].CGColor];
    colorLayer.locations  = @[@(-0.2), @(-0.1), @(0)];
    
    // 起始点
    colorLayer.startPoint = CGPointMake(0, 0);
    
    // 结束点
    colorLayer.endPoint   = CGPointMake(1, 0);
    
    CAShapeLayer *circle = [RootViewController LayerWithCircleCenter:CGPointMake(102, 100)
                                                              radius:80
                                                          startAngle:DEGREES(0)
                                                            endAngle:DEGREES(360)
                                                           clockwise:YES
                                                     lineDashPattern:nil];
    circle.strokeColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:circle];
    circle.strokeEnd = 1.f;
    colorLayer.mask = circle;
    
    _timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
    [_timer event:^{

        static int i = 0;
        if (i++ % 2 == 0)
        {
            CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"locations"];
            fadeAnim.fromValue = @[@(-0.2), @(-0.1), @(0)];
            fadeAnim.toValue   = @[@(1.0), @(1.1), @(1.2)];
            fadeAnim.duration  = 1.5;
            [colorLayer addAnimation:fadeAnim forKey:nil];
        }

    } timeInterval:NSEC_PER_SEC];
    [_timer start];
}

+ (CAShapeLayer *)LayerWithCircleCenter:(CGPoint)point
                                 radius:(CGFloat)radius
                             startAngle:(CGFloat)startAngle
                               endAngle:(CGFloat)endAngle
                              clockwise:(BOOL)clockwise
                        lineDashPattern:(NSArray *)lineDashPattern
{
    CAShapeLayer *layer = [CAShapeLayer layer];
    
    // 贝塞尔曲线(创建一个圆)
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0)
                                                        radius:radius
                                                    startAngle:startAngle
                                                      endAngle:endAngle
                                                     clockwise:clockwise];
    
    // 获取path
    layer.path = path.CGPath;
    layer.position = point;
    
    // 设置填充颜色为透明
    layer.fillColor = [UIColor clearColor].CGColor;
    
    // 获取曲线分段的方式
    if (lineDashPattern)
    {
        layer.lineDashPattern = lineDashPattern;
    }
    
    return layer;
}

@end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值