动画分类:
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//运算模式:平滑均匀
各种运算模式的直观比较如下图:
增加关键帧的方法:
[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。
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;
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:
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可以在合适的机会把异步、并发的操作同步到主线程去,并且能获得不错的性能。
相关文章