i0S - Core Animation(核心动画)

Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍。也就是说,使用少量的代码就可以实现非常强大的功能。
Core Animation可以用在Mac OS X和iOS平台。
Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。
要注意的是,Core Animation是直接作用在CALayer上的,并非UIView。
乔帮主在2007年的WWDC大会上亲自为你演示Core Animation的强大:点击查看视频

Core Animation类的继承关系图


Core Animation类的继承关系图.jpg

首先介绍两个重要的属性详情点击查看

CALayer的两个比较重要的属性positionanchorPoint
position和anchorPoint属性都是CGPoint类型的
position可以用来设置CALayer在父层中的位置,它是以父层的左上角为坐标原点(0, 0)
anchorPoint称为"定位点",它决定着CALayer身上的哪个点会在position属性所指的位置。它的x、y取值范围都是0~1,默认值为(0.5, 0.5)

一:CABasicAnimation-基本动画

基本Api介绍:
CAAnimation——所有动画对象的父类

 keyPath
 要改变的属性名称(传字符串)

 FromValue
 设置动画的初始值
 
 ToValue
 设置动画的到达值
 
 Autoreverses
 设定这个属性为 YES 时,在它到达目的地之后,动画的返回到开始的值,代替了直接跳转到开始的值,过渡平滑
 
 Duration
 设定开始值到结束值花费的时间。期间会被速度的属性所影响
 
 RepeatCount
 默认的是 0,动画只会播放一次。如果指定一个无限大的重复次数,使用 MAXFLOAT 。这个不应该和 repeatDration 属性一块使用
 
 RepeatDuration
 这个属性指定了动画应该被重复多久。动画会一直重复,直到设定的时间用完。同上它不应该和 repeatCount 一起使用
 
 RemovedOnCompletion
 这个属性默认为 YES,在指定的时间段完成后,动画就自动的从层上移除了
 
 Speed
 默认的值为 1.0.如果你改变这个值为 2.0,动画会用 2 倍的速度播放。这样的影响就是使持续时间减半。如果你指定的持续时间为 6 秒,速度为 2.0,动画就会播放 3 秒钟即一半的持续时间。
 
 BeginTime
 可以用来设置动画延迟执行时间,若想延迟1s,就设置为CACurrentMediaTime()+1,CACurrentMediaTime()为图层的当前时间
 

CAAnimation——动画填充模式

 FillMode
 这个属性一般和 RemovedOnCompletion 配合使用,保持动画状态。其中kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态.此时将RemovedOnCompletion设为NO

CAAnimation——速度控制函数

 TimingFunction
 控制动画运行的节奏.
 kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉 k
 CAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
 kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
 kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。

CAAnimation——动画代理方法

CAAnimation在分类中定义了代理方法,是给NSObject添加的分类,所以任何对象,成为CAAnimation的代理都可以
@interface NSObject (CAAnimationDelegate)

/* Called when the animation begins its active duration. */
动画开始的时候调用
- (void)animationDidStart:(CAAnimation *)anim;
动画停止的时候调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

@end

CABasicAnimation-Example

- (void)view1Animation {
    // 呼吸动画
    CABasicAnimation *animation =[CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = [NSNumber numberWithFloat:1.0f];
    animation.toValue = [NSNumber numberWithFloat:0.0f];
    animation.autoreverses = YES;    //回退动画(动画可逆,即循环)
    animation.duration = 1.0f;
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;//removedOnCompletion,fillMode配合使用保持动画完成效果
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [self.view1.layer addAnimation:animation forKey:@"aAlpha"];
}
- (void)view2Animation {
    
    // 设置旋转原点
    self.view2.layer.anchorPoint = CGPointMake(0.5, 0);
    CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //角度转弧度(这里用1,-1简单处理一下)
    rotationAnimation.toValue = [NSNumber numberWithFloat:1];
    rotationAnimation.fromValue = [NSNumber numberWithFloat:-1];
    rotationAnimation.duration = 1.0f;
    rotationAnimation.repeatCount = MAXFLOAT;
    rotationAnimation.removedOnCompletion = NO;
    rotationAnimation.autoreverses = YES;
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    rotationAnimation.fillMode = kCAFillModeForwards;
    [self.view2.layer addAnimation:rotationAnimation forKey:@"revItUpAnimation"];
}
- (void)view3Animation {
    
    CABasicAnimation *moveAnimation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    moveAnimation.duration = 0.8;//动画时间
    //动画起始值和终止值的设置
    moveAnimation.fromValue = @(180);
    moveAnimation.toValue = @(130);
    //一个时间函数,表示它以怎么样的时间运行
    moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    moveAnimation.repeatCount = MAXFLOAT;
    moveAnimation.repeatDuration = 100;
    moveAnimation.removedOnCompletion = NO;
    moveAnimation.fillMode = kCAFillModeForwards;
    //添加动画,后面有可以拿到这个动画的标识
    [self.view3.layer addAnimation:moveAnimation forKey:@"view3Animation"];
}

二:CAKeyframeAnimation-关键帧动画

CABasicAnimation:只能从一个数值(fromValue)变到另一个数值(toValue)
CAKeyframeAnimation:会使用一个NSArray保存这些数值

CAKeyframeAnimation-Example

- (void)view4Animation {
    //values方式实现
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    
    animation.keyPath = @"position";
    NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(50, 100)];
    NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(kWindowWidth - 50, 100)];
    NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(kWindowWidth - 50, kWindowHeight-50)];
    NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(50, kWindowHeight-50)];
    NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(50, 100)];
    animation.values = @[value1,value2,value3,value4,value5];
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.duration = 6.0f;
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.view4.layer addAnimation:animation forKey:@"values"];

}
- (void)view5Animation {
    // path方式实现
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position";
    CGMutablePathRef path = CGPathCreateMutable();
    //矩形线路
    CGPathAddRect(path, NULL, CGRectMake(50,100, kWindowWidth - 50,kWindowHeight - 50));
    animation.path=path;
    CGPathRelease(path);
    animation.repeatCount = MAXFLOAT;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.duration = 6.0f;
    animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.view4.layer addAnimation:animation forKey:@"path"];
    
}
- (void)view6Animation {
    
    //keyTimes演示
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    //animation.keyPath = @"transform.translation.x";
    animation.keyPath = @"position.x";
    animation.values   = @[@0, @20, @-20, @20, @0];
    animation.keyTimes = @[ @0, @(1 / 6.0), @(3 / 6.0), @(5 / 6.0), @1 ];
    animation.duration = 6;
    animation.additive = YES;
    [self.view4.layer addAnimation:animation forKey:@"keyTimes"];
    
}
- (void)view7Animation {
    // 跟随路径移动动画
    //创建路径
    UIBezierPath *bezierPath = [[UIBezierPath alloc] init];
    [bezierPath moveToPoint:CGPointMake(0, 450)];
    [bezierPath addCurveToPoint:CGPointMake(370, 500) controlPoint1:CGPointMake(350, 200) controlPoint2:CGPointMake(300, 600)]; //一个曲线
    //路径样式
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = bezierPath.CGPath;
    shapeLayer.fillColor = [UIColor clearColor].CGColor; //填充色<默认黑色>
    shapeLayer.strokeColor = [UIColor blueColor].CGColor; //线色
    shapeLayer.lineWidth = 2;
    [self.view.layer addSublayer:shapeLayer];
    
    CAKeyframeAnimation *animaiton = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    NSArray *rotationVelues = @[@(M_PI_4), @(-M_PI_4), @(M_PI_4)];
    animaiton.values = rotationVelues;
    animaiton.rotationMode = kCAAnimationRotateAuto;  //方向
    animaiton.duration = 3.0f;
    animaiton.keyTimes = @[@0.2 ,@0.8 ,@1];
    animaiton.path = bezierPath.CGPath;
    animaiton.repeatCount = HUGE_VALF;     //   #define    HUGE_VALF    1e50f
    [self.view4.layer addAnimation:animaiton forKey:@"path"];
    
}
- (void)popJumpAnimationView:(UIView *)sender {
    // 上下跳动动画
    CGFloat duration = 0.4f;
    CGFloat height = 25.f;
    CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];
    CGFloat currentTy = sender.transform.ty;
    animation.duration = duration;
    animation.values = @[@(currentTy), @(currentTy - height/4), @(currentTy-height/4*2), @(currentTy-height/4*3), @(currentTy - height), @(currentTy-height/4*3), @(currentTy -height/4*2), @(currentTy - height/4), @(currentTy)];
    animation.keyTimes = @[ @(0), @(0.025), @(0.085), @(0.2), @(0.5), @(0.8), @(0.915), @(0.975), @(1) ];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.repeatCount = 1;
    [sender.layer addAnimation:animation forKey:@"kViewShakerAnimationKey"];
}

三:CAAnimationGroup-动画组

CAAnimationGroup-Example

- (void)view8Animation {
    
    CABasicAnimation * animationScale = [CABasicAnimation animation];
    animationScale.keyPath = @"transform.scale";
    animationScale.toValue = @(0.1);
    
    CABasicAnimation *animationRota = [CABasicAnimation animation];
    animationRota.keyPath = @"transform.rotation";
    animationRota.toValue = @(M_PI_2);
    
    CAAnimationGroup * group = [[CAAnimationGroup alloc] init];
    group.duration = 3.0;
    group.fillMode = kCAFillModeForwards;
    group.removedOnCompletion = NO;
    group.repeatCount = MAXFLOAT;
    
    group.animations = @[animationScale,animationRota];
    [self.view5.layer addAnimation:group forKey:nil];
}

四:CATransition-转场动画

CATransitionApi介绍:

 CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。iOS比Mac OS X的转场动画效果少一点
 UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果
 动画属性:(有的属性是具备方向的,详情看下图)
 
/* The name of the transition. Current legal transition types include
 * `fade', `moveIn', `push' and `reveal'. Defaults to `fade'. */
 type
 动画过渡类型
 常见类型
  pageCurl 向上翻一页 
  pageUnCurl 向下翻一页 
  rippleEffect 滴水效果 
  suckEffect 收缩效果,如一块布被抽走 
  cube 立方体效果 
  oglFlip 上下翻转效果
 
/* An optional subtype for the transition. E.g. used to specify the
 * transition direction for motion-based transitions, in which case
 * the legal values are `fromLeft', `fromRight', `fromTop' and
 * `fromBottom'. */
 subtype
 动画过渡方向
 
 startProgress
 动画起点(在整体动画的百分比)
 
 endProgress
 动画终点(在整体动画的百分比)

CATransition-Example

- (void)view10Animation {
    self.imageView.userInteractionEnabled = YES;
    //添加手势
    UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
    leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.imageView addGestureRecognizer:leftSwipe];
    
    UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
    
    rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
    [self.imageView addGestureRecognizer:rightSwipe];
    
}

    static int _imageIndex = 0;
- (void)swipe:(UISwipeGestureRecognizer *)swipe {
    
    //转场代码与转场动画必须得在同一个方法当中.
    NSString *dir = nil;
    if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {
        
        _imageIndex++;
        if (_imageIndex > 4) {
            _imageIndex = 0;
        }
        NSString *imageName = [NSString stringWithFormat:@"%d.jpg",_imageIndex];
        self.imageView.image = [UIImage imageNamed:imageName];
        
        dir = @"fromRight";
    }else if (swipe.direction == UISwipeGestureRecognizerDirectionRight) {
        
        _imageIndex--;
        if (_imageIndex < 0) {
            _imageIndex = 4;
        }
        NSString *imageName = [NSString stringWithFormat:@"%d.jpg",_imageIndex];
        self.imageView.image = [UIImage imageNamed:imageName];
        
        dir = @"fromLeft";
    }
    
    //添加动画
    CATransition *anim = [CATransition animation];
    //设置转场类型
    anim.type = @"cube";
    //设置转场的方向
    anim.subtype = dir;
    anim.duration = 0.5;
    //动画从哪个点开始
    //anim.startProgress = 0.2;
    //anim.endProgress = 0.3;
    [self.imageView.layer addAnimation:anim forKey:nil];
}

多写代码、多写笔记、才能熟能生巧 !!!!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容