精华内容
下载资源
问答
  • 2014-12-20 15:45:24

    1. 实例代码

    1.1添加成员属性

    @property (nonatomic,strong) CADisplayLink *link;
    @property (nonatomic,assign) CFTimeInterval startTime ;
    1.2实例化displayLink,把link添加进runloop

    - (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:46
    iOS 帧动画播放工具,直接将GIFView添加,addAnimation开始播放,可添加多个。直播特效礼物播放
  • 北京智美方成网络科技有限公司IOS面试题。向数组中添加图片、利用UIImageView完成帧动画功能; 实现动画的开始、停止功能; 通过CALayer实现帧动画的暂停和恢复暂停功能。 代码逻辑: http://a3.work/a/oc/108.html
  • ios-UIImageView帧动画.zip

    2019-07-11 19:33:30
    UIImageView帧动画
  • iOS动画:UIImageView帧动画(完结)

    千次阅读 2019-05-13 17:16:52
    1.设置帧动画 var walkFrames = [ UIImage ( named : "walk01.png" ) ! , UIImage ( named : "walk02.png" ) ! , UIImage ( named : "walk03.png" ) ! , UIImage ( named : "walk04.png...

    这是iOS动画的最后一章,比较简单,我们来创建一只企鹅移动的动画
    image_1
    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()
    

    运行效果
    image_2

    展开全文
  • iOS基本动画/关键帧动画/利用缓动函数实现物理动画效果 先说下基本动画部分 基本动画部分比较简单, 但能实现的动画效果也很局限 使用方法大致为: #1. 创建原始UI或者画面 #2. 创建CABasicAnimation实例, 并设置...
  • IOS开发基础之核心动画 基础动画、关键、组动画案例 案例源码在我的主页里。实现效果图 // // 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 动画的原理与实现方式。 什么是动画 动画,顾名思义,就是能“动”的画。 人的眼睛对图像有短暂的记忆效应,所以当眼睛看到多...

    这篇文章不会教大家如何实现一个具体的动画效果,我会从动画的本质出发,来说说 iOS 动画的原理与实现方式。

    什么是动画

    动画,顾名思义,就是能“动”的画。
    人的眼睛对图像有短暂的记忆效应,所以当眼睛看到多张图片连续快速的切换时,就会被认为是一段连续播放的动画了。

    比如,中国古代的“走马灯”,就是用的这个原理。
    有些人还会在一个本子每页上手绘一些漫画,当快速翻页的时候,也会看到动画的效果,比如:


    图片来自网络

    计算机动画的实现方式

    动画是由一张张图片组成的,在计算机中,我们称每一张图片为 一帧画面

    如果我们想实现这么一个动画:一个水杯放在桌子的左边,移动到右边,那么我们实际操作的,只是水杯。
    所以动画的实现,只是对运动变化了的部分的处理。

    逐帧 与 关键帧

    类似于上面提到的手绘翻页方式,我们可以将这个水杯在每帧画面中的位置一一找出来,这样实现动画的方式就叫作 逐帧动画,我们需要处理动画中的每一帧。

    我们一般在计算机上用 FPS ( Frames Per Second) ,即 每秒的帧数 来表示动画的刷新速度,基于屏幕的刷新率等其他原因,在计算机上一般采用 60 FPS。
    如果运动变化幅度较缓,减半到 30 FPS 时,我们肉眼也是可接受的。
    较低的 FPS 会让我们有“卡顿”的感觉。

    逐帧动画是最直接的,但要处理的帧数太多,所以实现过程是会麻烦。

    计算机的工作就是来完成重复单调的工作的,所以,有些工作是可以考虑让计算机来完成的。


    上面的例子,可以变成一个涉及数学和物理的问题:一个杯子初始位置在左边,n秒后匀速运动到右边,那么在每 1/60 秒的时候,这个杯子的位置显然是可以计算出来的了。
    所以,我们其实只需要指定一些 关键 信息就能让计算机自己计算出每一帧杯子的位置了:

    • 起始位置,比如一个坐标 (0,0)
    • 结束位置,再比如一个坐标 (100,0)
    • 动画总时间,比如 0.25 秒
    • 匀速运动

    这种方式就称之为 关键帧动画。即我们只需要给定几个关键帧的画面信息,关键帧与关键帧之间的过渡帧都将由计算机自动生成。

    这里说的 关键帧动画,是指的广义上的一种动画制作方式,并不仅指 CAKeyframeAnimationCABasicAnimation的实现方式也属于 关键帧动画

    iOS 动画

    说完广义上的动画,就可以来说说 iOS 的动画了。
    先来说说动画的本质。

    动画的本质

    继续用上面的简单例子:一个 UIView 从 (0,0) 匀速移动到 (100,0)的动画,动画总时间是0.25秒。
    假设我们基于 60 FPS 来显示动画,那么在0.25秒内就应该有15帧画面,在每帧画面中,这个 UIViewx坐标,每次应移动 100/15 的距离。
    如果我们每隔 0.25/15 秒刷新一次UIViewx坐标,那么就能实现这个动画效果了。
    对于 x坐标而言,每帧的位置就可以通过一个基于时间变化量的函数来求得:x=f(t)

    所以,一个动画的本质,就是动画对象(这里是 UIView)的状态,基于时间变化的反应了。
    简单说,就是给定任意一个时刻,如果你都能得到这个动画对象的位置和、形状等等属性,你就能实现这个动画了。
    属性值的变化,既可能是位置、透明度、旋转角度等的变化,也包括形状的改变,比如从一条直线变化成一个圆圈,目标就是要得到变化过程中特定时刻的中间态。

    动画的实现

    我们也可将 iOS 的动画分为两大类:

    • 系统提供的 关键帧动画 实现方式;用户指定 关键 信息,系统实现动画过程,对用户而言操作起来会简单些。
    • 逐帧动画 实现方式;用户自己 出每一帧画面,系统操作方法简单,但用户操作的工作量就会大一些。

    逐帧动画实现方式

    简单的说,要实现逐帧的方式,就是需要 周期性 的调用 绘制 方法,绘制每帧的动画对象。

    这里说的 绘制,不光是指覆写 UIView- drawRect:的方法来手动重绘视图,也包括修改 UIView 它的属性,比如位置、颜色等。

    iOS 的动画都是基于 CALayer 的,iOS 的 UIView 背后都有一个对应的 CALayer 。对 UIView 的修改实际上都是对背后 CALayer 的修改。
    但如果在逐帧绘制的方法中修改了一个自建的 CALayer,这个 CALayer 不是对应某个 UIView 的,需注意系统的 隐式动画 的影响,后面会提到这点。

    周期性,就需要一个定时器来完成了,即 CADisplayLink
    CADisplayLinkNSTimer 比较类似,可以周期性的调用指定的方法。
    之所以用 CADisplayLink,是因为它是基于屏幕刷新率的,即屏幕每次刷新时就会触发调用。
    iPhone 的屏幕刷新率是 60 FPS。

    如果绘制过程过于复杂,不能在屏幕刷新一帧的时间内完成,可以考虑改为每隔一帧绘制,相当于是 30 FPS的刷新率。
    不然可能会使动画不连贯,有卡顿感。

    用逐帧方法绘制的原理不是很麻烦,麻烦的是绘制过程。
    对于一个复杂动画,你可能需要运用各种物理、几何知识去计算视图中间状态的信息。
    比如要实现一条直线卷曲变化为一个圆的动画,你就需要计算出中间态的曲线的弯曲程度和位置。

    著名的 facebook 的 pop 动画框架,就是使用 CADisplayLink 这种逐帧绘制的方式实现的。

    关键帧动画实现方式

    采用关键帧的方式来实现动画,要讲的内容相对逐帧的方式就多的多了。

    还是用 UIView 移动的简单例子。
    这里面有两个关键帧,起始帧和结束帧,除此之外还有2个关键信息:

    • 起始帧,变化信息:坐标为 (0,0)
    • 结束帧,变化信息:坐标为 (100,0)
    • 动画时间,0.25秒
    • 匀速运动

    坐标 信息是 UIView 的一个属性(实际是对应到 CALayer 的属性),在动画实现里,我们只需要指定起始和结束的两个关键值就够了,中间的过渡值都有系统自动生成。
    这里出现了两种值,一个是我们设定的,一个是系统生成的,所以要先在这里插入一个 模型层展现层 的概念了

    CALayer 的同一个属性值,会分别保存在模型层 modelLayer ,和展现层 presentationLayer 中。当我们修改属性值时,是修改的模型层的数值,动画时系统根据模型层的变化,生成的过渡值,是保存在展现层中的。

    CALayer 的对象里能直接访问到这两层的信息。
    CALayer 的底层实现实际不止这两层,但我们现在讨论动画的时候,可以只关心这两层。

    在整个动画过程中,呈现出来的过程是这样的:

    1. 动画前,显示模型层的当前值;
    2. 动画开始,切换显示展现层的值;
    3. 动画过程中,展现层的值根据时间变化,我们看到的实际是展现层的值在变化;
    4. 动画结束,切换回显示模型层的值,此时模型层的值应被修改为动画结束时的值。

    用一段代码来解释下动画过程。

        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 协议设定的。

    匀速运动是通过设置 CAAnimationtimingFunction 实现的,这是一个 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,其代理就是它对应的 UIViewUIView 就是用这种方式关闭了隐式动画。

    动画事务

    创建动画事务的目的是为了操作的原子性,保证动画的所有修改能同时生效。
    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 的时间控制,等等。感兴趣的话,可以再看看这些内容:



    文/胖花花(简书作者)
    原文链接: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的简单用法。文后有一个坑爹问题的临时解决方法,请知情人不吝
  • 关键帧动画: CAKeyframeAnimation 也属于 CAPropertyAnimation   关键帧动画 可以让我恩波精准的控制动画的效果 它的原理是把动画序列里面比较关键的帧提取出来 设置它的动画效果  values 属性 执行动画...
  • 用UIImageView做序列帧的时候,点击屏幕突然发现帧动画和图片消失了,在其他场景是没问题的,看了视图层级结构,UIImageView依然存在,只是帧动画和图片消失,经过学习研究发现是因为UIImageView传递的响应链中如果...
  • iOS ——逐帧动画

    千次阅读 2015-11-29 19:59:27
    1.UIImageView的帧动画 UIImageView可以让一系列的图片在特定的时间内按顺序显示 相关属性解析: animationImages:要显示的图片(一个装着UIImage的NSArray) animationDuration:完整地显示一次animationImages中...
  • 3.帧动画运用更为常见的是,运用了step(步长)去控制动画的频率 3.1声明静态变量 static long long steps; 3.2viewDidLoad - (void)viewDidLoad { [super viewDidLoad]; CADisplayLink *link =...
  • iOS:利用图实现动画效果,利用图实现动画效果,利用图实现动画效果
  • iOS图片播放帧动画

    2016-12-19 15:42:42
    解决了图片占用内存过大问题,每次都是只加载一张图片在内存。
  • **********基础知识: CVPixelBufferRef 是一种像素图片类型,属于 CoreVideo 模块的,在Camera 采集返回的数据里得到一个CMSampleBufferRef,而每个CMSampleBufferRef里则包含一个 ...CVPixelBufferRef是iOS视频采...
  • UIView 动画探究

    2021-01-02 19:00:00
    如果有多个低帧动画同时进行,但是这些低帧动画的刷新时刻不一定是同时触发的,那么整体来看有可能就会造成降帧效果不佳的情况(极端情况比如上图,两个 30 帧动画同时进行却刚好错开,造成 60 帧的效果)。...
  • 序列帧动画(以一个简单的TOM猫动画示例) 导入提前准备好的素材,对UIImageview和button按钮进行连线。 代码示例: - (IBAction)eat { NSMutableArray *arrayM=[NSMutableArray array]; for (int ...
  • 为了在一个帧动画结束后能立即施放内存。有以下例子:[imageView performSelector:@selector(setAnimationImages) withObject:nil after delay : 动画持续的时间];如果不使用延迟处理,会导致动画无法正常播放。 ...
  • 帧动画帧动画,一张张图片组合播放。类试电影效果。 使用: 一、UIView动画: 1.执行动画: (1)头尾式: /* 1.头尾式 */ - (void)startEndAnim{ //开启动画 [UIView beginAnimations:nil con...
  • YTAnimation iOS 动画主要是指 Core Animation 框架, Core Animation是 iOS 和 OS X 平台上负责图形渲染与动画的基础框架。...本文主要总结下平时常用的动画, 如: 基础动画(CABasicAnimation)、关键帧动画(CAKeyframeAn
  • ios中序列帧动画需要的方法

    千次阅读 2019-02-04 13:11:08
    animationDuration 几秒内完成动画数组 animationRepeatCount 重复次数 0代表无限次 startAnimating 开始动画 isAnimating 判断是否正在执行动画 stopAnimating 结束动画 // 1. 加载所有的图片 NSMutableArray &...
  • iOS之深入探究动画渲染降

    万次阅读 2021-10-16 20:50:40
    众所周知,刷新频率越高体验越好,对于 iOS app 的刷新频率应该是越接近越 60fps 越好,主动给动画,肯定会影响动画的体验。但是另一方面,我们也知道动画渲染的过程中需要消耗大量的 GPU 资源,所以给动画...
  • MBProgress,动画,帧动画,等待视图
  • 1.UIImageView中关于帧动画的一些属性和方法 2.汤姆猫示例
  • 该动画主要用到一个类,CAKeyframeAnimation关键帧动画的核心就是将整个动画的拆分成若干个小的动画,在将这些动画拼接成一个完整的动画,这种拆分可以通过该类的一个属性keytimes实现,设置不同的时间段呈现不同的...
  • iOS开发UI篇—核心动画(关键帧动画CAKeyframeAnimation) 一、简单介绍 是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而...
  • UIImageView的基本介绍 一实例化UIImageView ...四序列帧动画基础 属性说明 相关方法 五帧动画的代码 六帧动画的效果 UIImageView的基本介绍一、实例化UIImageView创建一个UIImageView可以使用以下的方法1. - initWith

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,601
精华内容 6,640
关键字:

ios 帧动画