動畫效果:
結合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