须知: 动画分为 UIView动画 和 核心动画,而核心动画是直接作用在CALayer上的。
CALayer
1.概念:
CALayer我们 称它叫做层. 在每个UIView内部都有 个layer这样 个属性. UIView之所以能够显 ,就是因为它 有这个层,才具有显示的功能. 我们通过操作CALayer对象,可以很方便地调整UIView的外观属性. 可以给UIView设置阴影,圆 ,边框等等…
2.操作Layer改变UIVIew的外观:
2.1.设置阴影
默认图层是有阴影的,图层不透明
_RedView.layer.shadowOpacity = 1; //阴影设置成不透明,很立体。
注意:只有设置好阴影不透明,才能去设置有关阴影的操作,否则看不到。
设置阴影的圆角
_RedView.layer.shadowRadius =10;
设置阴影的颜色,把UIKit转换成CoreGraphics框架,用.CG开头
_RedView.layer.shadowColor = [UIColor blueColor].CGColor;
设置阴影的偏移量
_RedView.layer.shadowOffset = CGSizeMake(-10, 10);
2.2.设置边框
①默认Layer边框为0;②设置的边框在里面 => 内容压缩
_RedView.layer.borderWidth = 2;
设置图层边框颜色,在图层中使用CoreGraphics的CGColorRef
RedView.layer.borderColor = [UIColor whiteColor].CGColor;
2.3.设置圆角
图层的圆角半径,圆角半径为宽度的一半, 就是一个圆
_RedView.layer.cornerRadius = 50;
3.操作layer改变UIImageView的外观.
设置图形边框
_imageView.layer.borderWidth = 2;
_imageView.layer.borderColor = [UIColor whiteColor].CGColor;
设置图片的圆角半径
_imageView.layer.cornerRadius = 50;
裁剪,超出裁剪区域的部分全部裁剪掉
_imageView.layer.masksToBounds = YES;
或者
_imageView.clipsToBounds = YES;
注意:
① UIImageView当中Image并不是直接添加在层上面的.这是添加在layer当中的contents里.
我们设置层的所有属性它只作用在层上面.对contents里面的东西并不起作用.所以我们看不到图片有圆角的效果.
想要让图片有圆角的效果.可以把Layer层上的masksToBounds这个属性设为YES,
当设为YES,把就会把超过根层以外的东西都给裁剪掉.
② clipsToBounds
是指视图上的子视图,如果超出父视图的部分就截取掉,
masksToBounds
却是指视图的图层上的子图层,如果超出父图层的部分就截取掉
4.layer的 CATransform3D属性.
旋转(只有旋转的时候才可以看出3D的效果.)
x,y,z 分别代表x,y,z轴.
CATransform3DMakeRotation(M_PI, 1, 0, 0);
self.imageV.layer.transform = CATransform3DMakeRotation(M_PI, 1, 1, 0);
self.imageV.layer.transform = CATransform3DRotate(self.imageV.layer.transform, M_PI, 1, 1, 0);
平移
CATransform3DMakeTranslation(x,y,z)
self.imageV.layer.transform = CATransform3DMakeTranslation(50, 50, 10);
self.imageV.layer.transform = CATransform3DTranslate(self.imageV.layer.transform, 50, 50, 10);
缩放
CATransform3DMakeScale(x,y,z);
self.imageV.layer.transform = CATransform3DMakeScale(0.5, 0.5, 1);
self.imageV.layer.transform = CATransform3DScale(self.imageV.layer.transform, 0.5, 0.5, 1);
综上:
带make: 结果基于最原始,故当再一次调用该方法时,除非参数改变,否则只会形变一次。
不带Make: 基于上一次,故当再一次调用该方法时,即使参数还是之前那个,但标准相当于上一次形变结果,永远是条件成立,
故只要调用,永远会形变。并且如果同时参数值改变,则相当于在”改变上加改变”形变成倍数改变!!
注意:
①UIView也有transform属性,UIView是属于UIKit框架。该属性类型为CGAffineTransform 属于CoreGraphics框架
故方法名以CGAffineTransform开头。
UIView的transform 属性只能操作二维形变,他的方法也分带Make和不带Make的。作用与CALayer里的一致。
②CALayer也有transform属性, CALayer是属于QuartzCore框架,该属性类型为CATransform3D,
故方法名以CATransform3D开头。
CALayer的transform属性可以用来设置三维形变
可以通过KVC的方式进行设置属性.但是CATransform3DMakeRotation它的值,是一个结构体, 所以要把结构转成对象.(优点:可以设置形变基于上一次,缺点:两条语句)
NSValue *value = [NSValue valueWithCATransform3D:CATransform3DMakeRotate( M_PI, 1, 1, 0)];
[self.imageV.layer setValue:value forKeyPath:@"transform”]; //结构体转对象时就已经声明了是旋转。
5.实际开发中通过KVC设置Layer的CATransform3D属性,通常写成如下形式,一步到位。
需求:
快速缩放,平移,二维的旋转时用KVC.(优点:只有一条语句 缺点:形变基于最原始的,当再一次调用它时,除非参数改变才会调用)
比如:
[_imageView.layer setValue:@0.5 forKeyPath:@"transform.scale"]; //后面就可以直接交代形变类型,一个语句搞定,更简洁
[self.imageV.layer setValue:@(M_PI) forKeyPath:@"transform.rotation.x”];
快速的进行缩放. 后面forKeyPath属性值不是乱写的.苹果文档当中给了相关的属性.
注意:
自定义UIView它内部的layer,是通过layerClass这个属性获得的。默认是[CALayer class]。
可通过重写该方法,设置默认的Layer为其他层
例如:
//设置自定义view的layer为复制层
+ (Class)layerClass { //该方法在awakeFromNib之前调用
return [CAReplicatorLayer class];
}
小结:常见的Layer有:
CAReplicatorLayer(复制层) ,CAShapeLayer(形状图层),CAGradientLayer(渐变层)
自定义CALayer
1.定义方式:
自定义CALayer的方式创建UIView的方式非常相似.
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(50, 50, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
给layer设置内容.
layer.contents = (id)[UIImage imageNamed:@"阿狸头像"].CGImage;
注意:
1注意视图View和Layer是分开的,Layer里可以添加很多Layer,视图View里也可以添加很多View,切记只能添加同类
2.视图View之所以显示,是因为有Layer存在,
3.Layer上添加内容:
①通过图层上下文画上去
②.利用Layer的Contents属性,直接给Layer设置内容。
4.Layer:
①不是透明的
②如果有内容则内容前后对称。
2.为什么要使用CGImageRef、CGColorRef?
答:为了保证可移植性,QuartzCore不能使用UIImage、UIColor,只能使用CGImageRef、CGColorRef
3.UIView和CALayer都能够显示东西,该怎样选择?
答: 对比CALayer,UIView多了一个事件处理的功能。也就是说,CALayer不能处理用户的触摸事件,而UIView可以。
所以:
如果显示出来的东西需要跟用户进行交互的话,用UIView;
如果不需要跟用户进行交互,用UIView或者CALayer都可以
CALayer的性能会高一些,因为它少了事件处理的功能,更加轻量级
position和anchorPoint(锚点)
1.概念
position和anchorPoint是CAlayer的两个属性.
我们以前修改一个控件的位置都是能过Frame的方式进行修改.
现在利用CALayer的position和anchorPoint属性也能够修改控件的位置. 这两个属性是配合使用的
2.position : 它是用来设置当前的layer在父控件当中的位置的.所以它的坐标原点为父控件的左上角(0.0)
3.anchorPoint : 它是决定CALayer身上哪一个点会在position属性所指的位置
anchorPoint它是以当前的layer左上角为原点(0.0)
它的取值范围是0~1,它的默认在中间也就是(0.5,0.5)的位置.
anchorPoint又称锚点.就是把锚点定到position所指的位置.
总结:
想要修改某个控件的位置,我们可以设置它的position点.
设置完毕后.layer身上的anchorPoint会自动定到position所在的位置.
隐式动画
1.了解什么是隐式动画前,要先了解是什么根层和非根层.
根层: UIView内部自动关联着的那个layer我们称它是根层.
非根层: 自己手动创建的层,称为非根层.
2.概念:
隐式动画就是当对非根层的部分属性进行修改时, 它会自动的产生一些动画的效果.
3.如何取消隐式动画?
首先要了解动画底层是怎么做的? => 动画的底层是包装成一个事务来进行的.
什么是事务? => 很多操作绑定在一起,当这些操作执行完毕后,才去执行下一个操作.如Block代码块
答:设置事务没有动画即可
开启事务
[CATransaction begin];
设置事务没有动画即可
[CATransaction setDisableActions:YES];
设置动画执行的时长
[CATransaction setAnimationDuration:2];
self.redL.cornerRadius = 50;
self.redL.backgroundColor = [UIColor blueColor].CGColor;
提交事务
[CATransaction commit];
注意:
1.在设置CALayer的动画过程中,开启事务和提交事务不写经测试也可以成功运行,但最好写上,毕竟规范。
2.取消隐式动画直接在动画事务中设置setDisableActions:为YES即可。
3.根层(系统自己创建的)是没有隐式动画的
1.Core Animation简介
① Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍 。 就是说使用少量的代码就可以实现非常强大的功能。
② Core Animation可以用在Mac OS X和iOS平台。
③ Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。
④ Core Animation是直接作用在CALayer上的,并非UIView。
乔帮主在2007年的WWDC大会上亲自为你演示Core Animation 的强大
2.核心动画的继承结构
注:黑色虚线代表“继承”某个类,红色虚线代表“遵守”某个协议
![Upload Snip20170204_1.png failed. Please try again.]
3.Core Animation的使用步骤
如果不是xcode5之后的版本,使用它需要先添加QuartzCore.framework和引入对应的框架
开发步骤:
1.首先得有CALayer
2.初始化一个CAAnimation对象,并设置一些动画相关属性
3.通过调用CALayer的addAnimation:forKey:方法,增加CAAnimation对象到CALayer中,这样就能开始执行动画了
4.通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画
4.CAAnimation——简介
<1> 是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类
属性说明:(红色代表来自CAMediaTiming协议的属性)
duration: 动画的持续时间
repeatCount: 重复次数,无限循环可以设置HUGE_VALF或者MAXFLOAT
repeatDuration: 重复时间
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示
动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
fillMode: 决定当前对象在非active时间段的行为。比如动画开始之前或者动画结束之后
beginTime: 可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,
CACurrentMediaTime()为图层的当前时间
timingFunction: 速度控制函数,控制动画运行的节奏
delegate: 动画代理
<2>CAAnimation——动画填充模式
fillMode属性值(要想fillMode有效,最好设置removedOnCompletion = NO)
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态.
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。
kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态
<3>CAAnimation——速度控制函数
速度控制函数(CAMediaTimingFunction)
kCAMediaTimingFunctionLinear(线性): 匀速,给你一个相对静态的感觉
kCAMediaTimingFunctionEaseIn(渐进): 动画缓慢进入,然后加速离
kCAMediaTimingFunctionEaseOut(渐出): 动画全速进入,然后减速的到达目的地
kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。
<4> CAAnimation——动画代理方法
CAAnimation在分类中定义了代理方法
@interface NSObject(CAAnimationDelegate)
- (void)animationDidStart:(CAAnimation*)anim;
- (void)animationDidStop:(CAAnimation*)animfinished:(BOOL)flag;
5.CALayer上动画的暂停和恢复
#pragma mark 暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime= [layer convertTime:CACurrentMediaTime() fromLayer:nil];
// 让CALayer的时间停止走动
layer.speed= 0.0;
// 让CALayer的时间停留在pausedTime这个时刻
layer.timeOffset= pausedTime;
}
#pragma mark 恢复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
// 1. 让CALayer的时间继续行走
layer.speed= 1.0;
// 2. 取消上次记录的停留时刻
layer.timeOffset= 0.0;
// 3. 取消上次设置的时间
layer.beginTime= 0.0;
// 4. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
// 5. 设置相对于父坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
6.CAPropertyAnimation
是CAAnimation的子类,也是个抽象类,要想创建动画对象,应该使用它的两个子类:
CABasicAnimation (基础动画)
CAKeyframeAnimation (关键帧动画)
属性说明:
keyPath:
通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。
比如,指定@“position”为keyPath,就修改CALayer的position属性的值,以达到平移的动画效果
7.CABasicAnimation——基础动画
基本动画,是CAPropertyAnimation的子类
属性说明:
fromValue:keyPath相应属性的初始值
toValue:keyPath相应属性的结束值
动画过程说明:
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue
keyPath内容是CALayer的可动画Animatable属性
如果fillMode=kCAFillModeForwards同时removedOnComletion=NO,那么在动画执行完毕后,图层会保持显示动画
执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。核心动画都是假象
8.CAKeyframeAnimation——关键帧动画
关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:
CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),
而CAKeyframeAnimation会使用一个NSArray保存这些数值
属性说明:
values:上述的NSArray对象。里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
path:
① 可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。
② path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略
keyTimes:
可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。
如果没有设置keyTimes,各个关键帧的时间是平分的
注意: CABasicAnimation可看做是只有2个关键帧CAKeyframeAnimation!!
9.CAAnimationGroup——动画组
动画组,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行
属性说明:
animations:用来保存一组动画对象的NSArray
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间
10.CATransition——转场动画
1. CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。
iOS比Mac OS X的转场动画效果少一点
注意:UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果
动画属性:
type: 动画过渡类型
subtype: 动画过渡方向
startProgress: 动画起点(在整体动画的百分比)
endProgress: 动画终点(在整体动画的百分比)
2.转场动画过度效果
![Upload Snip20170204_3.png failed. Please try again.]
3.使用UIView动画函数实现转场动画 — - 单视图
+ (void)transitionWithView:(UIView *)view
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)
options animations:(void(^)(void))animations
completion:(void(^)(BOOLfinished))completion;
参数说明:
duration:动画的持续时间
view:需要进行转场动画的视图
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
4.使用UIView动画函数实现转场动画 — - 双视图
+ (void)transitionFromView:(UIView *)fromView
toView:(UIView *)toView
duration:(NSTimeInterval)duration
options:(UIViewAnimationOptions)options
completion:(void(^)(BOOLfinished))completion;
参数说明:
duration:动画的持续时间
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
11.CADisplayLink
CADisplayLink是一种以屏幕刷新频率触发的时钟机制,每秒钟执行大约60次
CADisplayLink是一个计时器,可以使绘图代码与视图的刷新频率保持同步,而NSTimer无法确保计时器实际被触发的准确时间
使用方法:
定义CADisplayLink并制定触发调用方法,将CADisplayLink对象添加到主运行循环队列。
12.UIView动画与核心动画的区别
1.核心动画只作用在layer.
2.核心动画看到一切都是假像,它并没有修改View的真实位置.
什么时候使用核心动画, 什么时候使用UIView动画
当需要与用户进行交互时,必须和要使用 UIView动画 ,不需要时,两者都行
当想要做转场动画时,得要使用核心动画,转场类型比较多.
当要做帧动画时,根据路径做动画,必须得要使用核心动画.