iOS_CAAnimation核心动画

Core Animation, 中文翻译为核心动画,它是一组非常强大的动画处理 API.使用它能做出非常绚丽的动画效果, 而且往往事半功倍. 也就是说, 使用少量的代码就可以实现非常强大的功能. Core Animation可以用在Mac OS X和iOS平台. Core Animation的动画执行过程是在后台操作的, 不会阻塞主线程. 要注意的是, Core Animation是直接作用在CALayer上的.并非UIView.

Core Animation的使用步骤:

  1. 初始化一个CAAnimation对象,并设置一些动画的相关属性.
  2. 通过调用CALayeraddAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就能开始执行动画了.同样,我们可以通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画.
image

关于“x, y, z轴”的描述:

  1. x 轴表示水平直线轴,旋转方向为“上下旋转
  2. y 轴表示垂直直线轴,旋转方向为“左右旋转
  3. z 轴表示从平面向内穿透的直线,旋转方向为“平面旋转
  4. 如果x 轴为1, y 轴也为1,那么实现的旋转方向为“对角线旋转

CABasicAnimation的使用: (基本动画)

  1. CAPropertyAnimation子类属性解析:
  2. fromValue : keyPath相应属性的初始值
  3. toValue : keyPath相应属性的结束值
  4. 随着动画的进行,在长度为duration的持续时间内, keyPath相应属性的值从fromValue渐渐地变为toValue.
  5. 如果fillMode = kCAFillModeForwardsremovedOnComletion = NO; 那么在动画执行完毕后,图层会保持显示动画执行后的状态,但实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变.比如: CALayerpostion初始值为(0,0),CABasicAnimationfromValue(10,10),toValue(100,100),虽然动画执行完毕后图层保持在(100,100)这个位置,实质上图层的position还是为(0,0);
 //代码实现
 
 ------------------------------ ViewController.m------------------------------ 
 @interface ViewController()
 
 @property (nonatomic,weak) UIView *redView;
 
 @end
 
 @implementation ViewController

 - (void)viewDidLoad {
        [super viewDidLoad];
        
        //创建一个UIView
        UIView *redView = [[UIView alloc] init];
        redView.frame=CGRectMake(50,50,80,80);
        redView.backgroundColor= [UIColor redColor];
        [self.view addSubview:redView];
        self.redView = redView;
 }

演示代码一

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
        CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:@"position.y"]; 
        //设置动画结束位置
        anim1.toValue = @(300);
        //设置动画持续时间
        anim1.duration = 0.5;
        //重复
        anim1.repeatCount = 10;
        //把核心动画添加到layer中
        [self.redView.layer  addAnimation:anim1 forKey:@"anim1"];
}

展示效果:

注意:

方式一layer的真实位置还在原来的位置.

方式二layer的真实位置就是当前的位置.

//演示代码二
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {

        // 1.创建一个核心动画对象(基本动画) keyPath指的就是将来要修改的CALayer的属性名称
        CABasicAnimation*anim1 = [CABasicAnimation animationWithKeyPath:@"position"];
        anim1.fromValue= [NSValue valueWithCGPoint:CGPointMake(50,50)];
        anim1.toValue= [NSValue valueWithCGPoint:CGPointMake(150,250)];
        //设置layer执行完毕动画后,不要回去( 方式一 )注意: layer的真实位置还在原来的位置.
        anim1.removedOnCompletion = NO;//当核心动画执行完毕后不要从layer中移除
        anim1.fillMode = kCAFillModeForwards;

        //为animation对象设置代理(设置layer执行完毕动画后,不要回去 - 方法二)
        //这里的代理没有协议,叫做隐式代理
        anim1.delegate = self;
        //设置动画持续时间
        anim1.duration=2;
        // 2.把核心动画对象添加到对应的layer中,第二个参数表示是这个动画的一个"键",一个layer中可以添加多个核心动画
        [self.redView.layer addAnimation:anim1 forKey:@"anim1"];
}

//动画开始执行
 - (void)animationDidStart:(CAAnimation*)anim {
        NSLog(@"start...");
}

//动画结束执行
- (void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {
        // 注意: layer的真实位置就是当前的位置.
        self.redView.center = CGPointMake(150,250);
        NSLog(@"stop...");
}
@end
image

CAKeyframeAnimation的使用: (关键帧动画)

  1. CAPropertyAnimation的子类. 跟CABasicAnimation的区别:
  2. CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue). 而CAKeyframeAnimation 会使用一个NSArray保存这些数值. 属性解析如下:
  3. Values :就是上述的NSArray对象, 里面的元素称为“关键帧” (keyframe). 动画对象会在指定的时间(duration)内, 依次显示values数组中的每一个关键帧.
  4. Path: 可以设置一个CGPathRef \ CGMutablePathRef, 让层跟着路径移动. Path只对CALayer的anchorPointposition其作用.如果你设置了path, 那么values将被忽略.
  5. keyTimes :可以为对应的关键帧 制定对应的时间点.其取值范围为0到1.0.
    keyTimes中的每一个时间值都对应values中的每一帧, 当 keyTimes没有设置的时候,各个关键帧的时间是平分的.

//演示代码一通过values数组属性设置路径

//代码实现 
------------------------------ ViewController.m------------------------------
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
         // 1.创建一个关键帧动画
        CAKeyframeAnimation*animKey = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        animKey.duration=3.0;
        // 2.设置动画属性
        NSValue*p1 = [NSValue valueWithCGPoint:CGPointMake(50,150)];
        NSValue*p2 = [NSValue valueWithCGPoint:CGPointMake(250,150)];
        NSValue*p3 = [NSValue valueWithCGPoint:CGPointMake(50,450)];
        NSValue*p4 = [NSValue valueWithCGPoint:CGPointMake(250,450)];
        animKey.values=@[p1, p2, p3, p4];
        // 3.添加
        [self.redView.layer addAnimation:animKey forKey:@"animKey"];
 }

//演示代码二通过path来设置路径

- (void)viewDidLoad {
        [superviewDidLoad];
        //创建一个UIView
        UIView*redView = [[UIView alloc] init];
        redView.frame=CGRectMake(50,50,50,20);
        redView.backgroundColor= [UIColor redColor];
        [self.view addSubview:redView];
        self.redView= redView;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
        // 1.创建一个关键帧动画
        CAKeyframeAnimation*animKey = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        animKey.duration=3;
        //设置该属性的此枚举值会锁着旋转的角度做"自转"
        animKey.rotationMode = kCAAnimationRotateAuto;
        // 2.设置动画属性
        UIBezierPath*path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50,100,150,200)];
        animKey.path= path.CGPath;
        // 3.添加
        [self.redView.layer addAnimation:animKey forKey:@"animKey"];
}

案例三使用关键帧动画来实现图片抖动

实现的步骤是什么?

  1. 第一步,在视图加载完成之后首先来创建一个UIView.并为UIView设置内容.Layer的contents属性.
  2. 第二步,点击屏幕实现图片抖动效果,使用序列帧动画( values数组)来实现.
------------------------------ ViewController.m------------------------------

@interfaceViewController()

@property(nonatomic,weak)UIView*iconView;

@end

@implementationViewController
- (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColorlight GrayColor];
        UIView *iconView = [[UIView alloc] init];
        iconView.layer.contents = (__bridgeid_Nullable)([UIImage imageNamed:@"icon"].CGImage);
        iconView.frame  = CGRectMake(85,100,150,150);
        iconView.layer.cornerRadius = 30;
        iconView.layer.masksToBounds = YES;
        [self.view addSubview:iconView];
        self.iconView = iconView;
}
 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {
        // 1.创建一个关键帧动画
        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
        // 2.设置关键帧值数组
        anim.values=@[@(-M_PI_4*0.1*2),@(M_PI_4*0.1*2),@(-M_PI_4*0.1*2),];
        anim.repeatCount=CGFLOAT_MAX;
        // 3.把核心动画对象添加到layer中
        [self.iconView.layer addAnimation:anim forKey:@"icon_anim"];
}
@end

CAAnimationGroup的使用: (组动画)

CAAnimation的子类.可以保存一组动画对象, 将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行.属性解析如下:

  1. animations :用来保存一组动画对象的NSArray.默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间.
------------------------------ ViewController.m------------------------------

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event {

        // 1.创建一个组动画
        CAAnimationGroup*anim = [CAAnimationGroup animation];
        // 2.向组动画中添加各种子动画
        //旋转
        CABasicAnimation *anim1 = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        anim1.byValue=@(M_PI*2*1000); // transform.rotation.z表示以平面轴旋转1000圈
        //缩放
        CABasicAnimation *anim2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
        anim2.toValue=@(0.1);// transform.scale表示以x, y, z,三个轴进行缩放至原来尺寸的0.1倍
        //位移
        CAKeyframeAnimation *anim3 = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        anim3.path= [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50,100,150,200)].CGPath;
        // 3.设置属性,并把子动画添加到组动画中
        anim.animations=@[anim1, anim2, anim3];
        //包含平面旋转1000圈,缩放至原来尺寸的0.1倍,和椭圆路径进行动画,时长使用1.5秒来完成.
        anim.duration=1.5;
        anim.repeatCount=CGFLOAT_MAX;
        // 4.把动画添加到对应的layer中
        [self.redView.layer addAnimation:animforKey:@"group_anim"];
}

CATransition的使用: (转场动画)

CAAnimation的子类.用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果.

UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果.属性解析如下:

  1. type :动画过渡类型.
  2. Subtype :动画过渡方向.
  3. startProgress :动画起点(在整体动画的百分比).
  4. endProgress :动画终点(在整体动画的百分比).
image

需求一根据手势实现图片浏览器!可以直接在控件面板中向图片拖入手势.

展示效果:

image
image
image
------------------------------ ViewController.m------------------------------

@interfaceViewController()

@property(weak,nonatomic)IBOutletUIImageView*imgViewIcon;

//记录下标

@property(nonatomic,assign)intindex;

@end

@implementationViewController

- (void)viewDidLoad {

[superviewDidLoad];

self.imgViewIcon.userInteractionEnabled=YES;

}

//两个手势识别器同时连线到了这个方法中

- (IBAction)didRecognizeSwipeGesture:(UISwipeGestureRecognizer*)sender {
        if(sender.direction==UISwipeGestureRecognizerDirectionLeft) {
                self.index++;
        }else{
                self.index--;
        }
        //判断是否越界
        if(self.index>4) {
                self.index=0;
        }
        if(self.index<0) {
                self.index=4;
        }
        //拼接图片名称
        NSString*imgName = [NSString stringWithFormat:@"%d",self.index+1];
        //切换图片
        self.imgViewIcon.image= [UIImage imageNamed:imgName];
}
@end

需求二为图片添加转场动画对象(CATransiton).

  1. 创建一个转场动画对象.
  2. 设置转场动画的类型和子类型.
  3. 将转场动画添加到对应的控件身上.

特别注意:转场动画添加到哪个控件身上,就是哪个控件的整体进行转场的动画.

展示效果:

image
image
image
------------------------------ ViewController.m------------------------------

//两个手势识别器同时连线到了这个方法中
- (IBAction)didRecognizeSwipeGesture:(UISwipeGestureRecognizer*)sender {
        // 1.创建一个转场动画对象
        CATransition*anim = [CATransition animation];
        // 2.设置转场动画类型
        anim.type=@"cube";
        anim.duration=1.5;//动画时长
        if (sender.direction == UISwipeGestureRecognizerDirectionLeft) {
        // 2.设置转场动画的子类型
                anim.subtype=kCATransitionFromRight;
                self.index++;
        }else{
                // 2.设置转场动画的子类型
                anim.subtype=kCATransitionFromLeft;
                self.index--;
        }

        //判断是否越界
        if(self.index>4) {
                self.index=0;
        }

        if(self.index<0) {
                self.index=4;
        }

        //拼接图片名称
        NSString*imgName = [NSString stringWithFormat:@"%d",self.index+1];
        //切换图片
        self.imgViewIcon.image= [UIImage imageNamed:imgName];
        // 3.把转场动画添加到对应的控件身上
        [self.imgViewIcon.layer addAnimation:animforKey:@"anim1"];
}

需求三是用UIView动画函数实现转场动画->单视图.

展示效果:

image
image
image
------------------------------ ViewController.m------------------------------

//两个手势识别器同时连线到了这个方法中

- (IBAction)didRecognizeSwipeGesture:(UISwipeGestureRecognizer*)sender {
        if(sender.direction==UISwipeGestureRecognizerDirectionLeft) {
                self.index++;
        }else{
                self.index--;
        }
        //判断是否越界
        if(self.index>4) {
                self.index=0;
        }
        if(self.index<0) {
                self.index=4;
        }

        //拼接图片名称
        NSString*imgName = [NSString stringWithFormat:@"%d",self.index+1];
        //切换图片
        self.imgViewIcon.image= [UIImage imageNamed:imgName];
        //通过UIView来添加转场动画
        [UIView transitionWithView:self.imgViewIcon duration:0.5 options:UIViewAnimationOptionTransitionCurlUp animations:^{
                [UIView animateWithDuration:0.5animations:^{
                        self.imgViewIcon.alpha=0.4;
                }completion:^(BOOLfinished) {
                        [UIView animateWithDuration:0.5animations:^{
                                self.imgViewIcon.alpha=1.0;
                        }];
                }];
        }completion:^(BOOLfinished) {
                NSLog(@"动画完成!");
        }];
}
UIView转场动画单视图方法介绍.

+ (void)transitionWithView:(UIView*)view

duration:(NSTimeInterval)duration

options:(UIViewAnimationOptions)options

animations:(void(^__nullable)(void))animations completion:(void(^__nullable)(BOOLfinished))completion;

lduration :动画的持续时间

lview :需要进行转场动画的视图

loptions :转场动画的类型

lanimations :将改变视图属性的代码放在这个block中

lcompletion :动画结束后,会自动调用这个block

UIView转场动画双视图方法介绍.

+ (void)transitionFromView:(UIView*)fromView toView:(UIView*)toView

duration:(NSTimeInterval)duration

options:(UIViewAnimationOptions)options

completion:(void(^__nullable)(BOOLfinished))completion;

lduration :动画的持续时间

loptions :转场动画的类型

lanimations :将改变视图属性的代码放在这个block中

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

推荐阅读更多精彩内容