Core Animation

动画分类:

ios动画分为UIView类和CALayer类

两者区别:

@property (weak, nonatomic) IBOutlet UIView *oview;

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

    //打印动画块的位置

         NSLog(@"动画执行之前的位置:%@",NSStringFromCGPoint(self.oview.center));

         //首尾式动画

         [UIView beginAnimations:nil context:nil];

         //执行动画

         //设置动画执行时间

         [UIView setAnimationDuration:2.0];

         //设置代理

         [UIView setAnimationDelegate:self];

         //设置动画执行完毕调用的事件

         [UIViewsetAnimationDidStopSelector:@selector(didStopAnimation)];

         self.oview.center=CGPointMake(200,300);

         [UIView commitAnimations];

}

-(void)didStopAnimation {       

        NSLog(@"动画执行完毕");

         //打印动画块的位置

         NSLog(@"动画执行之后的位置:%@",NSStringFromCGPoint(self.oview.center));

}

输出动画执行之前的位置:{157, 147}

 动画执行完毕

动画执行之后的位置:{200, 300}

注意:由上可以看出UIView执行动画之后frame变了

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

    //1.创建核心动画

         CABasicAnimation *anima=[CABasicAnimation animation];

         //平移

         anima.keyPath=@"position";

         //设置执行的动画

         anima.toValue=[NSValue valueWithCGPoint:CGPointMake(200, 300)];

         //设置执行动画的时间

         anima.duration=2.0;

         //设置动画执行完毕之后不删除动画

         anima.removedOnCompletion=NO;

         //设置保存动画的最新状态

         anima.fillMode=kCAFillModeForwards;

     //    anima.fillMode=kCAFillModeBackwards;

         //设置动画的代理

         anima.delegate=self;

         //2.添加核心动画

         [self.oview.layer addAnimation:animaforKey:nil];

}

-(void)animationDidStart:(CAAnimation*)anim {

         //打印动画块的位置

     //    NSLog(@"动画开始执行前的位置:%@",NSStringFromCGPoint(self.customView.center));

         NSLog(@"动画开始执行前的位置:%@",NSStringFromCGPoint(self.oview.layer.position));

     }

 -(void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {

         //打印动画块的位置

         NSLog(@"动画执行完毕后的位置:%@",NSStringFromCGPoint(self.oview.layer.position));

}

输出:动画开始执行前的位置:{157, 147}

动画执行完毕后的位置:{157, 147}

注意:由上可以看出UIView执行动画之后frame没变

UIView动画:

UIView动画可以设置的动画属性有:

1、大小变化(frame)

2、拉伸变化(bounds)

3、中心位置(center)

4、旋转(transform)

5、透明度(alpha)

6、背景颜色(backgroundColor)

7、拉伸内容(contentStretch)

UIview类方法动画:

1)动画的开始和结束方法

1.1动画开始标记

[UIView beginAnimations:(nullable NSString*)context:(nullable void*)];

第一个参数:动画标识

第二个参数:附加参数,在设置了代理的情况下,此参数将发送到setAnimationWillStartSelector和setAnimationDidStopSelector所指定的方法。大部分情况下,我们设置为nil即可。

1.2结束动画标记

[UIView commitAnimations];

2)动画参数的设置方法

//动画持续时间

[UIView setAnimationDuration:(NSTimeInterval)];

//动画的代理对象

[UIView setAnimationDelegate:(nullableid)];

//设置动画将开始时代理对象执行的SEL

[UIView setAnimationWillStartSelector:(nullableSEL)];

//设置动画结束时代理对象执行的SEL

[UIView setAnimationDidStopSelector:(nullableSEL)];

//设置动画延迟执行的时间

[UIView setAnimationDelay:(NSTimeInterval)];

//设置动画的重复次数

[UIView setAnimationRepeatCount:(float)];

//设置动画的曲线

[UIView setAnimationCurve:(UIViewAnimationCurve)];

UIViewAnimationCurve的枚举值如下:

UIViewAnimationCurveEaseInOut,//慢进慢出(默认值)

UIViewAnimationCurveEaseIn,//慢进

UIViewAnimationCurveEaseOut,//慢出

UIViewAnimationCurveLinear//匀速

//设置是否从当前状态开始播放动画。假设上一个动画正在播放,且尚未播放完毕,我们将要进行一个新的动画:当为YES时:动画将从上一个动画所在的状态开始播放;当为NO时:动画将从上一个动画所指定的最终状态开始播放(此时上一个动画马上结束)

[UIView setAnimationBeginsFromCurrentState:YES];

//设置动画是否继续执行相反的动画

[UIView setAnimationRepeatAutoreverses:(BOOL)];

//是否禁用动画效果(对象属性依然会被改变,只是没有动画效果)。

[UIView setAnimationsEnabled:(BOOL)];

//设置视图的过渡效果。UIViewAnimationTransition的枚举值如下:

UIViewAnimationTransitionNone,//不使用动画

UIViewAnimationTransitionFlipFromLeft,//从左向右旋转翻页

UIViewAnimationTransitionFlipFromRight,//从右向左旋转翻页

UIViewAnimationTransitionCurlUp,//从下往上卷曲翻页

UIViewAnimationTransitionCurlDown,//从上往下卷曲翻页

第二个参数:需要过渡效果的View

第三个参数:是否使用视图缓存,YES:视图在开始和结束时渲染一次;NO:视图在每一帧都渲染

[UIView setAnimationTransition:(UIViewAnimationTransition)forView:(nonnull UIView*)cache:(BOOL)];

UIviewBlock动画:

1、最简洁的Block动画:包含时间和动画:

[UIView animateWithDuration:(NSTimeInterval)//动画持续时间

animations:^{

//执行的动画

}];

2、带有动画完成回调的Block动画

[UIView animateWithDuration:(NSTimeInterval)//动画持续时间

animations:^{

//执行的动画

}completion:^(BOOLfinished){

//动画执行完毕后的操作

}];

3、可设置延迟时间和过渡效果的Block动画

[UIView animateWithDuration:(NSTimeInterval)//动画持续时间

delay:(NSTimeInterval)//动画延迟执行的时间

options:(UIViewAnimationOptions)//动画的过渡效果

animations:^{

//执行的动画

}completion:^(BOOLfinished){

//动画执行完毕后的操作

}];

UIViewAnimationOptions的枚举值如下,可组合使用:

UIViewAnimationOptionLayoutSubviews//进行动画时布局子控件

UIViewAnimationOptionAllowUserInteraction//进行动画时允许用户交互

UIViewAnimationOptionBeginFromCurrentState//从当前状态开始动画

UIViewAnimationOptionRepeat//无限重复执行动画

UIViewAnimationOptionAutoreverse//执行动画回路

UIViewAnimationOptionOverrideInheritedDuration//忽略嵌套动画的执行时间设置

UIViewAnimationOptionOverrideInheritedCurve//忽略嵌套动画的曲线设置

UIViewAnimationOptionAllowAnimatedContent//转场:进行动画时重绘视图

UIViewAnimationOptionShowHideTransitionViews//转场:移除(添加和移除图层的)动画效果

UIViewAnimationOptionOverrideInheritedOptions//不继承父动画设置

UIViewAnimationOptionCurveEaseInOut//时间曲线,慢进慢出(默认值)

UIViewAnimationOptionCurveEaseIn//时间曲线,慢进

UIViewAnimationOptionCurveEaseOut//时间曲线,慢出

UIViewAnimationOptionCurveLinear//时间曲线,匀速

UIViewAnimationOptionTransitionNone//转场,不使用动画

UIViewAnimationOptionTransitionFlipFromLeft//转场,从左向右旋转翻页

UIViewAnimationOptionTransitionFlipFromRight//转场,从右向左旋转翻页

UIViewAnimationOptionTransitionCurlUp//转场,下往上卷曲翻页

UIViewAnimationOptionTransitionCurlDown//转场,从上往下卷曲翻页

UIViewAnimationOptionTransitionCrossDissolve//转场,交叉消失和出现

UIViewAnimationOptionTransitionFlipFromTop//转场,从上向下旋转翻页

UIViewAnimationOptionTransitionFlipFromBottom//转场,从下向上旋转翻页

4、Spring动画:

OS7.0后新增Spring动画(iOS系统动画大部分采用SpringAnimation,适用于所有可被添加动画效果的属性)

[UIView animateWithDuration:(NSTimeInterval)//动画持续时间

delay:(NSTimeInterval)//动画延迟执行的时间

usingSpringWithDamping:(CGFloat)//震动效果,范围0~1,数值越小震动效果越明显

initialSpringVelocity:(CGFloat)//初始速度,数值越大初始速度越快

options:(UIViewAnimationOptions)//动画的过渡效果

animations:^{

//执行的动画

}

completion:^(BOOLfinished){

//动画执行完毕后的操作

}];

5、Keyframes动画:

iOS7.0后新增关键帧动画,支持属性关键帧,不支持路径关键帧

[UIView animateKeyframesWithDuration:(NSTimeInterval)//动画持续时间

delay:(NSTimeInterval)//动画延迟执行的时间

options:(UIViewKeyframeAnimationOptions)//动画的过渡效果

animations:^{

//执行的关键帧动画

}completion:^(BOOL finished){

//动画执行完毕后的操作

}];

UIViewKeyframeAnimationOptions的枚举值如下,可组合使用:

UIViewAnimationOptionLayoutSubviews//进行动画时布局子控件

UIViewAnimationOptionAllowUserInteraction//进行动画时允许用户交互

UIViewAnimationOptionBeginFromCurrentState//从当前状态开始动画

UIViewAnimationOptionRepeat//无限重复执行动画

UIViewAnimationOptionAutoreverse//执行动画回路

UIViewAnimationOptionOverrideInheritedDuration//忽略嵌套动画的执行时间设置

UIViewAnimationOptionOverrideInheritedOptions//不继承父动画设置

UIViewKeyframeAnimationOptionCalculationModeLinear//运算模式:连续

UIViewKeyframeAnimationOptionCalculationModeDiscrete//运算模式:离散

UIViewKeyframeAnimationOptionCalculationModePaced//运算模式:均匀执行

UIViewKeyframeAnimationOptionCalculationModeCubic//运算模式:平滑

UIViewKeyframeAnimationOptionCalculationModeCubicPaced//运算模式:平滑均匀

各种运算模式的直观比较如下图:


Core Animation_第1张图片
动画模式

增加关键帧的方法:

[UIView addKeyframeWithRelativeStartTime:(double)//动画开始的时间(占总时间的比例)

relativeDuration:(double)//动画持续时间(占总时间的比例)

animations:^{

//执行的动画

}];

6、转场动画

6.1从旧视图转到新视图的动画效果

[UIView transitionFromView:(nonnull UIView*)toView:(nonnull UIView*)

duration:(NSTimeInterval) options:(UIViewAnimationOptions)

completion:^(BOOLfinished){

//动画执行完毕后的操作

}];

在该动画过程中,fromView会从父视图中移除,并讲toView添加到父视图中,注意转场动画的作用对象是父视图(过渡效果体现在父视图上)。

调用该方法相当于执行下面两句代码:

[fromView.superview addSubview:toView];

[fromView removeFromSuperview];

6.2单个视图的过渡效果

[UIView transitionWithView:(nonnull UIView*) duration:(NSTimeInterval)

options:(UIViewAnimationOptions)   animations:^{

//执行的动画

}completion:^(BOOL finished){

//动画执行完毕后的操作

}];

核心动画:

核心动画这个名字本身具有误导性。看到这个名字,大家很可能会认为这个框架(framework)的首要功能是动画,但事实上,动画只是这个框架的一个小的方面。这个框架之前的名字叫做Layer Kit。

核心动画是一个合成引擎,它的工作是尽可能快的将不同的可视化的内容合成到屏幕上。这个可视化内容是不同的层(layer),构成一个叫做层树(layer tree)的层次结构。

* Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。

* 要注意的是,Core Animation是直接作用在CALayer上的,并非UIView。


Core Animation_第2张图片

CAAnimation遵守CAMediaTiming和CAAction协议;注意CATransition和CATransaction;我们可以直接使用的有:CABasicAnimation,CAKeyframeAnimation,CASpringAnimation,CATransition,CAAnimationGroup

CAMediaTiming 

协议中定义了时间,速度,重复次数等。属性定义如下:

beginTime -> 用来设置动画延时,若想延迟1秒,就设置为CACurrentMediaTime()+1,其中CACurrentMediaTime()为图层当前时间。

duration -> 动画的持续时间。

speed -> 动画速率,决定动画时间的倍率。当speed为2时,动画时间为设置的duration的1/2。

timeOffset -> 动画时间偏移量。比如设置动画时长为3秒,当设置timeOffset为1.5时,当前动画会从中间位置开始,并在到达指定位置时,走完之前跳过的前半段动画。

repeatCount -> 动画的重复次数。

repeatDuration -> 动画的重复时间。

autoreverses -> 动画由初始值到最终值后,是否反过来回到初始值的动画。如果设置为YES,就意味着动画完成后会以动画的形式回到初始值。

fillMode -> 决定当前对象在非动画时间段的行为.比如动画开始之前,动画结束之后。

CAAnimation

核心动画基础类,不能直接使用

timingFunction -> 控制动画的节奏。系统提供的包括:kCAMediaTimingFunctionLinear (匀速),kCAMediaTimingFunctionEaseIn (慢进快出),kCAMediaTimingFunctionEaseOut (快进慢出),kCAMediaTimingFunctionEaseInEaseOut (慢进慢出,中间加速),kCAMediaTimingFunctionDefault (默认),当然也可通过自定义创建CAMediaTimingFunction。

removedOnCompletion -> 是否让图层保持显示动画执行后的状态,默认为YES,也就是动画执行完毕后从涂层上移除,恢复到执行前的状态,如果设置为NO,并且设置fillMode为kCAFillModeForwards,则保持动画执行后的状态。

CAPropertyAnimation

属性动画,针对对象的可动画属性进行效果的设置,不可直接使用。添加属性具体如下:

keyPath -> CALayer的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果。

additive -> 属性动画是否以当前动画效果为基础,默认为NO。

cumulative -> 指定动画是否为累加效果,默认为NO。

valueFunction -> 此属性配合CALayer的transform属性使用。

CABasicAnimation

基础动画,通过keyPath对应属性进行控制,需要设置fromValue以及toValue。添加属性如下:

fromValue -> keyPath相应属性的初始值。

toValue -> keyPath相应属性的结束值。

byValue -> 在不设置toValue时,toValue = fromValue + byValue,也就是在当前的位置上增加多少。

CAKeyframeAnimation 

关键帧动画,同样通过keyPath对应属性进行控制,但它可以通过values或者path进行多个阶段的控制。属性如下:

values -> 关键帧组成的数组,动画会依次显示其中的每一帧。

path -> 关键帧路径,动画进行的要素,优先级比values高,但是只对CALayer的anchorPoint和position起作用。

keyTimes -> 每一帧对应的时间,如果不设置,则各关键帧平分设定时间。

timingFunctions -> 每一帧对应的动画节奏。

calculationMode -> 动画的计算模式,系统提供了对应的几种模式。

tensionValues -> 动画张力控制。

continuityValues -> 动画连续性控制。

biasValues -> 动画偏差率控制。

rotationMode -> 动画沿路径旋转方式,系统提供了两种模式。

CATransition

 转场动画,系统提供了很多酷炫效果。属性如下:

type -> 转场动画类型。

subtype -> 转场动画方向。

startProgress -> 动画起点进度(整体的百分比)。

endProgress -> 动画终点进度(整体的百分比)。

filter -> 自定义转场。

CAAnimationGroup 

动画组,方便对于多动画的统一控制管理。

animations -> 所有动画效果元素的数组。


CASpringAnimation 

带有初始速度以及阻尼指数等物理参数的属性动画。我们可以把它看成在不绝对光滑的地面上,一个弹簧拴着别小球,那么我们可以这么理解他的属性(物理知识请问一下牛顿大叔):

mass -> 小球质量,影响惯性。

stiffness -> 弹簧的劲度系数。

damping -> 阻尼系数,地面的摩擦力。

initialVelocity -> 初始速度,相当于给小球一个初始速度(可正可负,方向不同)

settlingDuration -> 结算时间,根据上述参数计算出的预计时间,相对于你设置的时间,这个时间比较准确。

异步绘制:

UIKit的单线程天性意味着寄宿图通畅要在主线程上更新,这意味着绘制会打断用户交互,甚至让整个app看起来处于无响应状态。我们对此无能为力,但是如果能避免用户等待绘制完成就好多了。

CATiledLayer:

使用这个layer的好处之一就是,它不需要你自己计算分块显示的区域,它自己直接提供,你只需要根据这个区域计算图片相应区域,然后画图就可以了。

第二个好处就是它是在其他线程画图,不会因为阻塞主线程而导致卡顿。

第三个好处就是它自己实现了只在屏幕区域显示图片,屏幕区域外不会显示,而且当移动图片时,它会自动绘制之前未绘制的区域,当你缩放时它也会自动重绘。

对tileSize进行设置,首先是将它赋值成视图的大小,它将分四次绘制;注意切片越多内存峰值越小但是绘制速度变慢

tiledLayer.tileSize =self.bounds.size; 


Core Animation_第3张图片
切片

drawsAsynchronously:

iOS 6中,苹果为CALayer引入了这个令人好奇的属性,drawsAsynchronously属性对传入 -drawLayer:inContext: 的CGContext进行改动,允许CGContext延缓绘制命令的执行以至于不阻塞用户交互。

它与CATiledLayer使用的异步绘制并不相同。它自己的 -drawLayer:inContext: 方法只会在主线程调用,但是CGContext并不等待每个绘制命令的结束。相反地,它会将命令加入队列,当方法返回时,在后台线程逐个执行真正的绘制。

根据苹果的说法。这个特性在需要频繁重绘的视图上效果最好(比如我们的绘图应用,或者诸如UITableViewCell之类的),对那些只绘制一次或很少重绘的图层内容来说没什么太大的帮助。

YYKIT异步绘制原理:

void(^display)(CGContextRef context,CGSizesize,BOOL(^isCancelled)(void));  //先声明一个block可以使用context,然后可以用CoreGraphy画图

在需要画图的地方: dispatch_async(GCAsyncLayerGetDisplayQueue(), ^{

   UIGraphicsBeginImageContextWithOptions(size, opaque, scale);

     CGContextRef context = UIGraphicsGetCurrentContext();

     display(context, size, isCancelled); //调用block

 UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

})

避免延迟解压:

DEMO地址:https://github.com/HeroOneHY/CoreAnimation-

coreAnimation和runloop:


Core Animation_第4张图片

iOS 的显示系统是由 VSync 信号驱动的,VSync 信号由硬件时钟生成,每秒钟发出 60 次(这个值取决设备硬件,比如 iPhone 真机上通常是 59.97)。iOS 图形服务接收到 VSync 信号后,会通过 IPC 通知到 App 内。App 的 Runloop 在启动后会注册对应的 CFRunLoopSource 通过 mach_port 接收传过来的时钟信号通知,随后 Source 的回调会驱动整个 App 的动画与显示。

Core Animation 在 RunLoop 中注册了一个 Observer,监听了 BeforeWaiting 和 Exit 事件。这个 Observer 的优先级是 2000000,低于常见的其他 Observer。当一个触摸事件到来时,RunLoop 被唤醒,App 中的代码会执行一些操作,比如创建和调整视图层级、设置 UIView 的 frame、修改 CALayer 的透明度、为视图添加一个动画;这些操作最终都会被 CALayer 捕获,并通过 CATransaction 提交到一个中间状态去(CATransaction 的文档略有提到这些内容,但并不完整)。当上面所有操作结束后,RunLoop 即将进入休眠(或者退出)时,关注该事件的 Observer 都会得到通知。这时 CA 注册的那个 Observer 就会在回调中,把所有的中间状态合并提交到 GPU 去显示;如果此处有动画,CA 会通过 DisplayLink 等机制多次触发相关流程。


以上是iOS硬件和系统底层的runloop原理,那我们来看看,咱们怎么利用它来做些事情。


所有针对属性的修改和提交,总有些任务是必需放入主线程执行的。当出现这种任务时,manager会把任务封装并提交到一个全局的容器去。咱们的manager也在 RunLoop 中注册了一个 Observer,监视的事件和 CA 一样,但优先级比 CA 要低。当 RunLoop 进入休眠前、CA 处理完事件后,manager 就会执行该 loop 内提交的所有任务。

通过这种机制,manager可以在合适的机会把异步、并发的操作同步到主线程去,并且能获得不错的性能。

相关文章

iOS 底层Runloop的详解

深入iOS系统底层之指令集介绍

你可能感兴趣的:(Core Animation)