-
2014-12-20 15:45:24
1. 实例代码
1.1添加成员属性
1.2实例化displayLink,把link添加进runloop@property (nonatomic,strong) CADisplayLink *link; @property (nonatomic,assign) CFTimeInterval startTime ;
- (void)viewDidLoad { [super viewDidLoad]; self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)]; [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; }
1.3实现监听方法- (void)update:(CADisplayLink *)sender { // 判断是否第一次执行此方法 if (self.startTime == 0) { self.startTime = sender.timestamp; //把link的时间戳赋值给startTime } CFTimeInterval deltaTime = sender.timestamp - self.startTime; // 每次执行此方法都会判断传进来的时间戳 和 存储的startTime 之差是否>= 1 if (deltaTime >= 1) { NSLog(@"每秒输出1次"); self.startTime = sender.timestamp; // 更新存储的startTime } }
1.4打印结果2014-12-20 15:54:36.634 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:37.651 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:38.667 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:39.684 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:40.684 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:41.701 帧动画[11110:60b] 每秒输出1次
2014-12-20 15:54:42.702 帧动画[11110:60b] 每秒输出1次
1.5CADisplayLink的其他属性
修改一下实例代码
#import "QKViewController.h" @interface QKViewController () - (IBAction)pauseButton; @property (nonatomic,strong) CADisplayLink *link; @property (nonatomic,assign) CFTimeInterval startTime ; @end @implementation QKViewController // 记录update第几次被调用 static int count; - (void)viewDidLoad { [super viewDidLoad]; // 初始化link self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)]; // 添加进runloop [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; // 打印调方法前的属性值 NSLog(@"默认的frameInterval = %d",self.link.frameInterval); NSLog(@"调用前: duration = %f,timestamp = %f",self.link.duration,self.link.timestamp); // 修改调用频率,改成60,意味着屏幕刷新60次,才去调用update:方法 self.link.frameInterval = 60; } - (void)update:(CADisplayLink *)sender { // 每调一下update:方法,记录调用次数 count ++; // 打印调用时的属性值 NSLog(@"duration = %f , timestamp = %f ,第%d次调用",self.link.duration,self.link.timestamp,count); // 调用60次后,移除Link if (count == 60) { [self.link removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; } } // 点击storyboard的按钮触发该方法:pause属性的示例,它是个BOOL值,可以让Link开始或停止 - (IBAction)pauseButton { self.link.paused = !self.link.paused; // 停用Link,一定要调 -(void)invalidate [self.link invalidate]; // 安全起见,把指针清空 self.link = nil; }
2014-12-20 16:58:15.465 帧动画[11680:60b] 默认的frameInterval = 1
2014-12-20 16:58:15.466 帧动画[11680:60b] 调用前: duration = 0.000000,timestamp = 0.000000
2014-12-20 16:58:15.474 帧动画[11680:60b] duration = 0.016667 , timestamp = 80880.508529 ,第1次调用
2014-12-20 16:58:16.466 帧动画[11680:60b] duration = 0.016667 , timestamp = 80881.500962 ,第2次调用
2014-12-20 16:58:17.466 帧动画[11680:60b] duration = 0.016667 , timestamp = 80882.500537 ,第3次调用
2014-12-20 16:58:18.466 帧动画[11680:60b] duration = 0.016667 , timestamp = 80883.500228 ,第4次调用
2014-12-20 16:58:19.466 帧动画[11680:60b] duration = 0.016667 , timestamp = 80884.499834 ,第5次调用
2014-12-20 16:58:20.467 帧动画[11680:60b] duration = 0.016667 , timestamp = 80885.500925 ,第6次调用
1.6总结
默认frameInterval=1, 1代表屏幕刷新1次,就调1次方法.改成60,意味着屏幕刷新60次,才调一次方法
调方法前: duration = 0.000000,timestamp = 0.000000,只有调用方法后,这2个属性才有值
无论修改frameInterval数值为多少,duration都不会变,duration代表相邻2次屏幕刷新时间的时间间隔,由苹果控制
timestamp,是CAAnimation的时间格式,格式比较特殊.有点像计算机时间,相对1907.1.1的偏移量.
更多相关内容 -
iOS 单帧动画播放
2018-05-15 11:26:46iOS 帧动画播放工具,直接将GIFView添加,addAnimation开始播放,可添加多个。直播特效礼物播放 -
帧动画控制(实现帧动画的开始、暂停、继续和停止功能)(面试题)
2018-12-17 17:10:46北京智美方成网络科技有限公司IOS面试题。向数组中添加图片、利用UIImageView完成帧动画功能; 实现动画的开始、停止功能; 通过CALayer实现帧动画的暂停和恢复暂停功能。 代码逻辑: http://a3.work/a/oc/108.html -
ios-UIImageView帧动画.zip
2019-07-11 19:33:30UIImageView帧动画 -
iOS动画:UIImageView帧动画(完结)
2019-05-13 17:16:521.设置帧动画 var walkFrames = [ UIImage ( named : "walk01.png" ) ! , UIImage ( named : "walk02.png" ) ! , UIImage ( named : "walk03.png" ) ! , UIImage ( named : "walk04.png...这是iOS动画的最后一章,比较简单,我们来创建一只企鹅移动的动画
1.设置帧动画var walkFrames = [ UIImage(named: "walk01.png")!, UIImage(named: "walk02.png")!, UIImage(named: "walk03.png")!, UIImage(named: "walk04.png")! ] let totalDuration = 1.0 func loadWalkAnimation() { penguin.animationImages = walkFrames penguin.animationDuration = totalDuration / 3 penguin.animationRepeatCount = 3 }
animtionImages:存储帧动画的所有帧图像。
animationDuration:告诉UIKit动画一次动画迭代需要持续多长时间。
animationRepeatCount:控制动画的重复次数当点击左右按钮时,更改企鹅朝向
var isLookingRight: Bool = true { didSet { let xScale: CGFloat = isLookingRight ? 1 : -1 penguin.transform = CGAffineTransform(scaleX: xScale, y: 1) slideButton.transform = penguin.transform } } @IBAction func actionLeft(_ sender: AnyObject) { isLookingRight = false } @IBAction func actionRight(_ sender: AnyObject) { isLookingRight = true }
在actionLeft中添加动画开始,当点击左侧按钮时,帧图像将开始切换播放动画:
penguin.startAnimating()
在actionLeft中添加企鹅行走动画
UIView.animate(withDuration: totalDuration, delay: 0, options: .curveEaseOut, animations: { self.penguin.center.x -= self.walkSize.width }, completion: nil)
在actionRight中添加向右行走的代码:
penguin.startAnimating() UIView.animate(withDuration: totalDuration, delay: 0, options: .curveEaseOut, animations: { self.penguin.center.x += self.walkSize.width }, completion: nil )
行走的动画就完成了,现在我们添加跳跃和滑行的动画,当滑行时修改penguin帧图像
@IBAction func actionSlide(_ sender: AnyObject) { loadSlideAnimation() penguin.startAnimating() } func loadSlideAnimation() { penguin.animationImages = slideFrames penguin.animationDuration = totalDuration penguin.animationRepeatCount = 1 }
当点击跳跃调用actionSlide方法时,将会执行新的动画效果,但是会发现,图像尺寸被放大了,因为原来的动画帧尺寸就比较大,所以我们需要修改其大小。
@IBAction func actionSlide(_ sender: AnyObject) { loadSlideAnimation() penguin.frame = CGRect(x: penguin.frame.origin.x, y: penguinY+(walkSize.height-slideSize.height), width: slideSize.width, height: slideSize.height) penguin.startAnimating() }
添加滑行的动画
UIView.animate(withDuration: totalDuration - 0.02, delay: 0.0, options: .curveEaseOut, animations: { self.penguin.center.x += self.isLookingRight ? self.slideSize.width : -self.slideSize.width }) { (_) in }
动画完成后还原企鹅动画
self.penguin.frame = CGRect(x: self.penguin.frame.origin.x, y: self.penguinY, width: self.walkSize.width, height: self.walkSize.height) self.loadWalkAnimation()
运行效果
-
iOS 基本动画、关键帧动画、利用缓动函数实现物理动画效果
2021-01-21 19:49:00iOS基本动画/关键帧动画/利用缓动函数实现物理动画效果 先说下基本动画部分 基本动画部分比较简单, 但能实现的动画效果也很局限 使用方法大致为: #1. 创建原始UI或者画面 #2. 创建CABasicAnimation实例, 并设置... -
IOS开发基础之核心动画 基础动画、关键帧、组动画案例
2021-02-21 23:28:32IOS开发基础之核心动画 基础动画、关键帧、组动画案例 案例源码在我的主页里。实现效果图 // // ViewController.m // 30-核心动画 // // Created by 鲁军 on 2021/2/21. // #import "ViewController.h" @interface...IOS开发基础之核心动画 基础动画、关键帧、组动画案例
案例源码在我的主页里。实现效果图
// // ViewController.m // 30-核心动画 // // Created by 鲁军 on 2021/2/21. // #import "ViewController.h" @interface ViewController () @property(nonatomic,weak)CALayer *layer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; UIView *redView =[[UIView alloc] init]; redView.frame =CGRectMake(100, 100, 20, 20); redView.backgroundColor =[UIColor redColor]; self.layer=redView.layer ; [self.view addSubview:redView]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ //组动画 CAAnimationGroup *group = [[CAAnimationGroup alloc] init]; //创建动画对象 (做什么动画) CABasicAnimation *anim = [[CABasicAnimation alloc]init]; anim.keyPath = @"transform.rotation"; anim.byValue =@(2*M_PI*10); CAKeyframeAnimation *anim1=[[CAKeyframeAnimation alloc] init]; anim1.keyPath = @"position"; UIBezierPath * path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:1]; anim1.path = path.CGPath; group.animations=@[anim,anim1]; group.duration = 3; group.repeatCount = INT_MAX; // 重复的次数 //怎么做动画 //添加动画(对谁做动画) [self.layer addAnimation:group forKey:nil]; } //关键帧 -(void)test2{ //关键帧 //创建动画对象 (做什么动画) CAKeyframeAnimation *anim = [[CAKeyframeAnimation alloc] init]; //怎么做动画 anim.keyPath=@"position"; /* NSValue *v1 =[NSValue valueWithCGPoint:CGPointMake(100, 100)]; NSValue *v2 =[NSValue valueWithCGPoint:CGPointMake(150, 100)]; NSValue *v3 =[NSValue valueWithCGPoint:CGPointMake(100, 150)]; NSValue *v4 =[NSValue valueWithCGPoint:CGPointMake(150,150 )]; anim.values =@[v1,v2,v3,v4]; */ UIBezierPath * path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:1]; anim.path = path.CGPath; anim.duration = 2; anim.repeatCount = INT_MAX; // 重复的次数 //添加动画(对谁做动画) [self.layer addAnimation:anim forKey:nil]; } //基础动画 -(void)testbaseAnimation{ //创建动画对象 (做什么动画) CABasicAnimation *animation = [[CABasicAnimation alloc] init]; //怎么做动画 animation.keyPath = @"position.x"; /*animation.fromValue =@(10); 从哪 animation.toValue = @(300); 到哪 */ //每次加10px animation.byValue = @(10); //不回去原来的地方 animation.fillMode = kCAFillModeForwards; animation.removedOnCompletion=NO; //添加动画(对谁做动画) [self.layer addAnimation:animation forKey:nil]; } @end
// // LJView.m // 30-核心动画 // // Created by 鲁军 on 2021/2/21. // #import "LJView.h" @implementation LJView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. */ - (void)drawRect:(CGRect)rect { // Drawing code UIBezierPath * path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:2*M_PI clockwise:1]; [path stroke]; } @end
-
iOS 动画原理与实现--帧动画、逐帧动画、CALayer
2016-12-30 16:56:43这篇文章不会教大家如何实现一个具体的动画效果,我会从动画的本质出发,来说说 iOS 动画的原理与实现方式。 什么是动画 动画,顾名思义,就是能“动”的画。 人的眼睛对图像有短暂的记忆效应,所以当眼睛看到多...这篇文章不会教大家如何实现一个具体的动画效果,我会从动画的本质出发,来说说 iOS 动画的原理与实现方式。
什么是动画
动画,顾名思义,就是能“动”的画。
人的眼睛对图像有短暂的记忆效应,所以当眼睛看到多张图片连续快速的切换时,就会被认为是一段连续播放的动画了。比如,中国古代的“走马灯”,就是用的这个原理。
有些人还会在一个本子每页上手绘一些漫画,当快速翻页的时候,也会看到动画的效果,比如:
图片来自网络计算机动画的实现方式
动画是由一张张图片组成的,在计算机中,我们称每一张图片为 一帧画面 。
如果我们想实现这么一个动画:一个水杯放在桌子的左边,移动到右边,那么我们实际操作的,只是水杯。
所以动画的实现,只是对运动变化了的部分的处理。逐帧 与 关键帧
类似于上面提到的手绘翻页方式,我们可以将这个水杯在每帧画面中的位置一一找出来,这样实现动画的方式就叫作 逐帧动画,我们需要处理动画中的每一帧。
我们一般在计算机上用 FPS ( Frames Per Second) ,即 每秒的帧数 来表示动画的刷新速度,基于屏幕的刷新率等其他原因,在计算机上一般采用 60 FPS。
如果运动变化幅度较缓,减半到 30 FPS 时,我们肉眼也是可接受的。
较低的 FPS 会让我们有“卡顿”的感觉。逐帧动画是最直接的,但要处理的帧数太多,所以实现过程是会麻烦。
计算机的工作就是来完成重复单调的工作的,所以,有些工作是可以考虑让计算机来完成的。
上面的例子,可以变成一个涉及数学和物理的问题:一个杯子初始位置在左边,n秒后匀速运动到右边,那么在每 1/60 秒的时候,这个杯子的位置显然是可以计算出来的了。
所以,我们其实只需要指定一些 关键 信息就能让计算机自己计算出每一帧杯子的位置了:- 起始位置,比如一个坐标 (0,0)
- 结束位置,再比如一个坐标 (100,0)
- 动画总时间,比如 0.25 秒
- 匀速运动
这种方式就称之为 关键帧动画。即我们只需要给定几个关键帧的画面信息,关键帧与关键帧之间的过渡帧都将由计算机自动生成。
这里说的 关键帧动画,是指的广义上的一种动画制作方式,并不仅指
CAKeyframeAnimation
,CABasicAnimation
的实现方式也属于 关键帧动画iOS 动画
说完广义上的动画,就可以来说说 iOS 的动画了。
先来说说动画的本质。动画的本质
继续用上面的简单例子:一个
UIView
从 (0,0) 匀速移动到 (100,0)的动画,动画总时间是0.25秒。
假设我们基于 60 FPS 来显示动画,那么在0.25秒内就应该有15帧画面,在每帧画面中,这个UIView
的 x坐标,每次应移动 100/15 的距离。
如果我们每隔 0.25/15 秒刷新一次UIView
的 x坐标,那么就能实现这个动画效果了。
对于 x坐标而言,每帧的位置就可以通过一个基于时间变化量的函数来求得:x=f(t) 。所以,一个动画的本质,就是动画对象(这里是
UIView
)的状态,基于时间变化的反应了。
简单说,就是给定任意一个时刻,如果你都能得到这个动画对象的位置和、形状等等属性,你就能实现这个动画了。
属性值的变化,既可能是位置、透明度、旋转角度等的变化,也包括形状的改变,比如从一条直线变化成一个圆圈,目标就是要得到变化过程中特定时刻的中间态。动画的实现
我们也可将 iOS 的动画分为两大类:
- 系统提供的 关键帧动画 实现方式;用户指定 关键 信息,系统实现动画过程,对用户而言操作起来会简单些。
- 逐帧动画 实现方式;用户自己 画 出每一帧画面,系统操作方法简单,但用户操作的工作量就会大一些。
逐帧动画实现方式
简单的说,要实现逐帧的方式,就是需要 周期性 的调用 绘制 方法,绘制每帧的动画对象。
这里说的 绘制,不光是指覆写
UIView
的- drawRect:
的方法来手动重绘视图,也包括修改UIView
它的属性,比如位置、颜色等。iOS 的动画都是基于
CALayer
的,iOS 的UIView
背后都有一个对应的CALayer
。对UIView
的修改实际上都是对背后CALayer
的修改。
但如果在逐帧绘制的方法中修改了一个自建的CALayer
,这个CALayer
不是对应某个UIView
的,需注意系统的 隐式动画 的影响,后面会提到这点。而 周期性,就需要一个定时器来完成了,即
CADisplayLink
。
CADisplayLink
与NSTimer
比较类似,可以周期性的调用指定的方法。
之所以用CADisplayLink
,是因为它是基于屏幕刷新率的,即屏幕每次刷新时就会触发调用。
iPhone 的屏幕刷新率是 60 FPS。如果绘制过程过于复杂,不能在屏幕刷新一帧的时间内完成,可以考虑改为每隔一帧绘制,相当于是 30 FPS的刷新率。
不然可能会使动画不连贯,有卡顿感。用逐帧方法绘制的原理不是很麻烦,麻烦的是绘制过程。
对于一个复杂动画,你可能需要运用各种物理、几何知识去计算视图中间状态的信息。
比如要实现一条直线卷曲变化为一个圆的动画,你就需要计算出中间态的曲线的弯曲程度和位置。著名的 facebook 的 pop 动画框架,就是使用
CADisplayLink
这种逐帧绘制的方式实现的。关键帧动画实现方式
采用关键帧的方式来实现动画,要讲的内容相对逐帧的方式就多的多了。
还是用
UIView
移动的简单例子。
这里面有两个关键帧,起始帧和结束帧,除此之外还有2个关键信息:- 起始帧,变化信息:坐标为 (0,0)
- 结束帧,变化信息:坐标为 (100,0)
- 动画时间,0.25秒
- 匀速运动
坐标 信息是
UIView
的一个属性(实际是对应到CALayer
的属性),在动画实现里,我们只需要指定起始和结束的两个关键值就够了,中间的过渡值都有系统自动生成。
这里出现了两种值,一个是我们设定的,一个是系统生成的,所以要先在这里插入一个 模型层 和 展现层 的概念了CALayer
的同一个属性值,会分别保存在模型层 modelLayer ,和展现层 presentationLayer 中。当我们修改属性值时,是修改的模型层的数值,动画时系统根据模型层的变化,生成的过渡值,是保存在展现层中的。在
CALayer
的对象里能直接访问到这两层的信息。
而CALayer
的底层实现实际不止这两层,但我们现在讨论动画的时候,可以只关心这两层。在整个动画过程中,呈现出来的过程是这样的:
- 动画前,显示模型层的当前值;
- 动画开始,切换显示展现层的值;
- 动画过程中,展现层的值根据时间变化,我们看到的实际是展现层的值在变化;
- 动画结束,切换回显示模型层的值,此时模型层的值应被修改为动画结束时的值。
用一段代码来解释下动画过程。
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; view.backgroundColor = [UIColor redColor]; [self.view addSubview:view]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(50, 0)]; animation.toValue = [NSValue valueWithCGPoint:CGPointMake(150, 0)]; [view.layer addAnimation:animation forKey:nil]; // view.frame = CGRectOffset(view.frame, 100, 0);
你会发现动画结束后,
view
又跳回了原来的位置,这是因为最后一行代码注释了,而这行代码的功能就是实现第4步,将模型层的值修改为动画结束时的值。动画实现
代码中的
CABasicAnimation
就是真正的动画实现部分,也就是设定关键帧信息的地方。将动画加入
CALayer
的代码定义为:
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
接受的类型是CAAnimation
类型,有下面这些子类:CABasicAnimation
,可设定起始结束两个关键帧的信息。CAKeyframeAnimation
,除首尾外,还可添加多个中间关键点。CAAnimationGroup
,可组合多个动画,因为上面两种动画一次只能设置一个属性值。CATransition
,图层过渡动画,默认是淡入。比如修改一个CALayer
的背景色时,是从初始色慢慢淡入过渡到结束色。
可修改为新颜色把旧颜色顶出去等效果。还可使用CIFilter
滤镜做过渡效果,一些开源UIViewController
的过渡动画使用了这种方式。
动画中,除了属性值外,我们还设置了两个和时间有关的信息:动画时间0.25秒,运动方式是匀速运动。
动画持续时间很简单,是通过
CAAnimation
遵守的CAMediaTiming
协议设定的。匀速运动是通过设置
CAAnimation
的timingFunction
实现的,这是一个CAMediaTimingFunction
类的对象。之前已经说到,动画过程实际是一个时间的函数,横坐标是时间的变化值,纵坐标是动画属性的变化量。那么我们就可以在一个直角坐标系中,通过作图来画出这个函数。比如匀速运动的图形,就是一条通过原点的直线。
所以这个类的功能就是画出一条曲线,来表示时间和属性变化之间的关系。而画图的方法,是使用的是画贝叶斯曲线的方法。
系统提供了几个常用的函数,比如
kCAMediaTimingFunctionLinear
就是匀速运动;kCAMediaTimingFunctionEaseInEaseOut
就是一般系统动画的默认值,渐入渐出,即在动画开始和结束的时候速度稍慢些。
图片来源自网络隐式动画
上面的过程,我们是 显式 的向一个
CALayer
添加了一个动画,所以这种方式叫做 显式动画。
对应的,还有 隐式动画,即系统自动添加上的动画。CALayer *layer = [CALayer layer]; layer.backgroundColor = [UIColor greenColor].CGColor; layer.frame = CGRectMake(0, 0, 100, 100); [self.view.layer addSublayer:layer]; layer.frame = CGRectOffset(layer.frame, 100, 0);
这段代码里,我们没有添加
CAAnimation
动画,但 layer 不是直接变化到新的位置,而是有一个动画效果。
这就是 隐式动画 的效果。当我们改变
CALayer
的一个可动画的属性值时,就会触发系统的隐式动画。
可动画的属性值,可以在CALayer
的文档中找到,属性说明中标有 Animatable 的,就是可自动添加动画的属性。但是,有一个例外,对于
UIView
背后对应的CALayer
,系统关闭了隐式动画,所以当我们直接修改UIView
或者是其底层的CALayer
时,变化是直接生效的,没有动画效果。所以当我们在逐帧方式生成动画时,是可以直接修改
UIView
或者是其底层的CALayer
的信息。
但是如果修改的是一个自建的单独CALayer
时,帧与帧之间的变化还是会触发系统的默认隐式动画,这个时候就需要我们来手动关闭隐式动画。
当快速动画的时候不会察觉到这点,但这明显会带来性能上的浪费。隐式动画所做的事情和显示动画是一样的,我们设置的属性值都是模型层的数值,而系统会自动添加属性对应的
CAAnimation
动画到CALayer
上。UIView
有一系列的animateWithDuration
动画方法,在这些方法中UIView
会恢复隐式动画,所以在动画的 block 中修改属性时,又会触发隐式动画。
那么系统是如果知道对一个属性应该添加哪种动画呢,这就需要让
CAAction
协议登场了。当修改一个
CALayer
的属性时,它会通过- actionForKey:
来查询这个属性对应的 action,而 key 就是对应的属性名称。
CAAnimation
遵守CAAction
协议,返回的 action 其实是个CAAnimation
动画。
也就是说,CALayer
通过- actionForKey:
来查询某个属性被修改时,需要调用哪个动画去展现这个变化。
一般默认返回的是CABasicAnimation
,默认动画时间 0.25秒,时间函数为渐入渐出 kCAMediaTimingFunctionEaseInEaseOut。- actionForKey:
查询 action 的步骤有4步,在这个方法中有详细的说明。
其中一种方式就是通过CALayer
的 delegate 返回 action。而对于UIView
背后对应的CALayer
,其代理就是它对应的UIView
,UIView
就是用这种方式关闭了隐式动画。动画事务
创建动画事务的目的是为了操作的原子性,保证动画的所有修改能同时生效。
CATransaction
就是动画事务的操作类。在创建隐式动画的时候,系统也会隐式的创建一个动画事务,以保证所有的动画能同时进行。
除此之外,还可以显式的创建一个事务。
显式事务中可以定义事务中所有动画的运行时间和时间函数,此外,还有这个方法+ (void)setDisableActions:(BOOL)flag
能显式的关闭这个事务中的 action 查询操作。
关闭了查询也就是关闭了动画效果,属性值的变化就会立即生效,而没有动画效果了:[CATransaction begin]; [CATransaction setDisableActions:YES]; ///... layer.frame = CGRectOffset(layer.frame, 100, 0); ///... [CATransaction commit];
注意别把 CATransaction 和 CATransition 搞混了,一个单词是 transaction 事务,另一个是 transition 转变。
对比 总结
关键帧动画的实现方式,只需要修改某个属性值就可以了,简单方便,但涉及的深层次内容较多,需要更多的理解和练习。
采用逐帧动画的实现方式,实现原理简单,但绘制动画的过程要复杂。如果动画过程处理的事情较多,也会带来较大的开销,就有可能造成动画帧数的下降,出现卡顿的现象,因此需要较多的测试和调试。
动画绘制的过程中,会要求较多的数学、物理等知识来计算中间态的数据。但这两种方式也不是绝对分离开的。
关键帧动画实现方式,一般只能对系统实现了可动画的属性做动画处理,但其实也是允许实现自定义属性的动画处理的。
这就需要自己来实现系统中自动计算过渡帧的操作了,也就是逐帧实现动画的方式了。
实现自定义属性的动画可以参考这篇文章: Layer 中自定义属性的动画对于 iOS 系统提供的动画方法,上面只是从整体的角度作了一个全面的整理,还有很多细节内容没有写出来,比如
CALayer
的三维变换、CAKeyframeAnimation
的延路径动画,CAMediaTiming
的时间控制,等等。感兴趣的话,可以再看看这些内容:- 苹果官方文档 Core Animation Programming Guide
- iOS Core Animation: Advanced Techniques -- 中文翻译
- objc中国 动画专题 中的 动画解释
文/胖花花(简书作者)
原文链接:http://www.jianshu.com/p/13c231b76594
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。 -
iOS CAKeyframeAnimation关键帧动画
2021-01-12 10:50:52本篇文章简单的介绍一下CAKeyframeAnimation关键帧动画,之前的一篇文章介绍过CABasicAnimation,这个关键帧动画和CABasicAnimation很像,甚至有过之而无不及。一起来看看吧。 -
iOS 关键帧动画 详解
2016-03-14 13:21:45不仅如此,这还是吸引我做iOS开发的一大原因,因为在iOS上给界面实现一些像样的动画实在是太轻松了! 这里就介绍一下iOS的block-based animation的简单用法。文后有一个坑爹问题的临时解决方法,请知情人不吝 -
iOS 核心动画-关键帧动画
2015-09-18 21:36:51关键帧动画: CAKeyframeAnimation 也属于 CAPropertyAnimation 关键帧动画 可以让我恩波精准的控制动画的效果 它的原理是把动画序列里面比较关键的帧提取出来 设置它的动画效果 values 属性 执行动画... -
【iOS】UIImageView点击屏幕,帧动画和图片消失
2020-09-21 19:08:57用UIImageView做序列帧的时候,点击屏幕突然发现帧动画和图片消失了,在其他场景是没问题的,看了视图层级结构,UIImageView依然存在,只是帧动画和图片消失,经过学习研究发现是因为UIImageView传递的响应链中如果... -
iOS ——逐帧动画
2015-11-29 19:59:271.UIImageView的帧动画 UIImageView可以让一系列的图片在特定的时间内按顺序显示 相关属性解析: animationImages:要显示的图片(一个装着UIImage的NSArray) animationDuration:完整地显示一次animationImages中... -
iOS 帧动画运用之雪花动画
2014-12-20 23:01:353.帧动画运用更为常见的是,运用了step(步长)去控制动画的频率 3.1声明静态变量 static long long steps; 3.2viewDidLoad - (void)viewDidLoad { [super viewDidLoad]; CADisplayLink *link =... -
iOS:利用帧图实现动画效果
2018-06-19 14:29:43iOS:利用帧图实现动画效果,利用帧图实现动画效果,利用帧图实现动画效果 -
iOS图片播放帧动画
2016-12-19 15:42:42解决了图片占用内存过大问题,每次都是只加载一张图片在内存。 -
iOS之GIF动画和视频帧的处理、图片转换成视频
2020-01-15 18:04:56**********基础知识: CVPixelBufferRef 是一种像素图片类型,属于 CoreVideo 模块的,在Camera 采集返回的数据里得到一个CMSampleBufferRef,而每个CMSampleBufferRef里则包含一个 ...CVPixelBufferRef是iOS视频采... -
UIView 动画降帧探究
2021-01-02 19:00:00如果有多个低帧动画同时进行,但是这些低帧动画的刷新时刻不一定是同时触发的,那么整体来看有可能就会造成降帧效果不佳的情况(极端情况比如上图,两个 30 帧动画同时进行却刚好错开,造成 60 帧的效果)。... -
iOS开发UI篇—iOS开发中动画设置(帧动画)
2015-07-20 12:09:00序列帧动画(以一个简单的TOM猫动画示例) 导入提前准备好的素材,对UIImageview和button按钮进行连线。 代码示例: - (IBAction)eat { NSMutableArray *arrayM=[NSMutableArray array]; for (int ... -
IOS每天15个注意点系列之UI-帧动画与图片浏览
2015-09-13 18:50:02为了在一个帧动画结束后能立即施放内存。有以下例子:[imageView performSelector:@selector(setAnimationImages) withObject:nil after delay : 动画持续的时间];如果不使用延迟处理,会导致动画无法正常播放。 ... -
iOS:UIView动画与帧动画
2019-04-14 17:33:41帧动画: 帧动画,一张张图片组合播放。类试电影效果。 使用: 一、UIView动画: 1.执行动画: (1)头尾式: /* 1.头尾式 */ - (void)startEndAnim{ //开启动画 [UIView beginAnimations:nil con... -
YTAnimation:iOS动画集锦, swift, 核心动画, 基础动画,关键帧动画, 组动画, 过渡动画, 进度条,项目案例
2021-05-16 05:10:57YTAnimation iOS 动画主要是指 Core Animation 框架, Core Animation是 iOS 和 OS X 平台上负责图形渲染与动画的基础框架。...本文主要总结下平时常用的动画, 如: 基础动画(CABasicAnimation)、关键帧动画(CAKeyframeAn -
ios中序列帧动画需要的方法
2019-02-04 13:11:08animationDuration 几秒内完成动画数组 animationRepeatCount 重复次数 0代表无限次 startAnimating 开始动画 isAnimating 判断是否正在执行动画 stopAnimating 结束动画 // 1. 加载所有的图片 NSMutableArray &... -
iOS之深入探究动画渲染降帧
2021-10-16 20:50:40众所周知,刷新频率越高体验越好,对于 iOS app 的刷新频率应该是越接近越 60fps 越好,主动给动画降帧,肯定会影响动画的体验。但是另一方面,我们也知道动画渲染的过程中需要消耗大量的 GPU 资源,所以给动画降帧... -
ios-MBProgress自定义帧动画.zip
2019-07-11 18:51:18MBProgress,动画,帧动画,等待视图 -
IOS1.7-UIImageView的帧动画相关属性和方法 (示例汤姆猫)
2015-01-11 18:51:461.UIImageView中关于帧动画的一些属性和方法 2.汤姆猫示例 -
ios 关键帧动画简单使用,实现view卡片切换
2018-07-11 16:35:03该动画主要用到一个类,CAKeyframeAnimation关键帧动画的核心就是将整个动画的拆分成若干个小的动画,在将这些动画拼接成一个完整的动画,这种拆分可以通过该类的一个属性keytimes实现,设置不同的时间段呈现不同的... -
iOS开发UI篇—核心动画(关键帧动画)
2016-12-28 18:53:11iOS开发UI篇—核心动画(关键帧动画CAKeyframeAnimation) 一、简单介绍 是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而... -
iOS学习笔记-011.UIImageView的基本介绍和帧动画
2017-01-17 11:06:14UIImageView的基本介绍 一实例化UIImageView ...四序列帧动画基础 属性说明 相关方法 五帧动画的代码 六帧动画的效果 UIImageView的基本介绍一、实例化UIImageView创建一个UIImageView可以使用以下的方法1. - initWith