1. 程式人生 > >iOS CoreAnimation 逐幀動畫 CADisplayLink

iOS CoreAnimation 逐幀動畫 CADisplayLink

逐幀動畫 CADisplayLink

動畫效果:

結合runloop 實現 每次螢幕重新整理都會執行此方法(每秒接近60此)

在此方法更新圖片, 或者更新layer的某個狀態實現動畫效果,感覺不到動畫的停滯效果


當然UIImageView通過設定animationImages的屬性, 然後startAnimating方法播放這組照片,也

可以達到逐幀的動畫效果, 但是存在很大的效能問題,並且一旦設定完圖片中間的過程就無法控

制了,

利用定時器NSTimer定時更新圖片也可以達到逐幀的效果, 這種可以解決一次性載入多個圖片

的效能問題, 而且播放也可以控制, 但是可能會因為系統執行某個方法而讓動畫變得斷斷續續

的連續性問題

這裡系統提供了CADisplayLink物件, CADidsplayLink是一個定時器, 與timer不同的

是,CADidsplayLink的重新整理週期同螢幕完全一致, 螢幕重新整理的週期是每秒60次,使其完全感覺不

到動畫的停滯情況

iOS程式在執行後就進入到一個訊息迴圈中(這個訊息迴圈被稱為"主執行迴圈"), 這個迴圈相當

於一個死迴圈中, 始終等待使用者輸入, 將CADisplayLink加入到主執行迴圈佇列後, 它的時鐘周

期就和主執行迴圈保持一致, 而主執行迴圈週期就是螢幕重新整理週期.CADidsplayLink加入到主運

行迴圈佇列後就會迴圈呼叫目標方法, 完成逐幀動畫,

這裡裡不得不強調的是逐幀動畫效能勢必較低,但是對於一些事物的運動又不得不選擇使用

逐幀動畫,例如人的運動,這是一個高度複雜的運動,基本動畫、關鍵幀動畫是不可能解決

的。所大家一定要注意在迴圈方法中儘可能的降低演算法複雜度,同時保證迴圈過程中記憶體峰

值儘可能低。下面以一個魚的運動為例為大家演示一下逐幀動畫。

//
//  LinkViewController.m
//  CAKeyframeAnimation
//
//  Created by 帝炎魔 on 16/5/26.
//  Copyright © 2016年 帝炎魔. All rights reserved.
//

#import "LinkViewController.h"

#define IMAGE_COUNT 10

@interface LinkViewController ()
{
    CALayer *_layer;
    int _index;
    NSMutableArray *_images;
}

@end

@implementation LinkViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 設定背景
    // layer 有個屬性可以直接設定內容 ----> 背景圖片
    self.view.layer.contents = (id)[UIImage imageNamed:@"bg"].CGImage;
    
    // 建立影象顯示圖層
    _layer = [[CALayer alloc] init];
    _layer.bounds = CGRectMake(0, 0, 87, 32);
    _layer.position = CGPointMake(self.view.center.x, self.view.center.y);
    [self.view.layer addSublayer:_layer];
    
    // 由於小魚的圖片比較小, 所以直接建立
    _images = [NSMutableArray array];
    for (int i = 0; i < 10; ++i) {
        NSString *imageName = [NSString stringWithFormat:@"fish%i.png", i];
        UIImage *image = [UIImage imageNamed:imageName];
        [_images addObject:image];
    }
    
    // 定義時鐘物件
    CADisplayLink *displayLink  = [CADisplayLink displayLinkWithTarget:self selector:@selector(step)];
    
    // 新增時鐘物件到主執行迴圈
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
    //  新增動畫
    [self addAnimation];
    
    // Do any additional setup after loading the view.
}

#pragma mark ---- 新增關鍵幀動畫 --- > 給魚一個遊動的路線
-(void)addAnimation
{
    // 1. 建立動畫物件
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 430, 600);
    CGPathAddCurveToPoint(path, NULL, 100, 600, 400, 200, -10, 50);
    animation.path = path;
    
   
    
    animation.repeatCount = HUGE_VALF;
    animation.duration = 8.0;
    animation.removedOnCompletion = NO;
    
    [_layer addAnimation:animation forKey:@"fishAnimation"];
    
     CGPathRelease(path);
    
}

#pragma mark --- 每次螢幕重新整理都會執行一次此方法(每秒接近60次)
- (void)step

{
    // 定義一個變數記錄執行次數
    static int a = 0;
    if (++a % 10  == 0) {
        UIImage *image = _images[_index];
        _layer.contents = (id)image.CGImage; // 更新圖片
        _index = (_index + 1) % IMAGE_COUNT;
    }
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end