在app的引導頁中,經常需要動態展示加載和交互過程,本文主要是對Gif動畫的調研,技術要求如下:
- 支持復雜的動態效果
- 易于維護
- 易于開發
- 兼容iOS7和小屏
- 高性能
Gif動畫
優點
使用Gif動畫方式展示動態效果,具有很多優點,開發維護比較簡單,工作量小,只需設計師提供動畫即可,相比原生制作動畫效率很高。Gif還能夠實現很復雜、酷炫的動畫特效,甚至有些是原生無法實現的。Gif對系統版本,對屏幕尺寸沒有什么要求,兼容性較好。
缺點
當然Gif也存在一些缺點,它僅支持單頁動畫,對于連續性的多頁面動畫則無能為力,比如隨著引導頁滑動,一個按鈕將從第一頁飛到第二頁。它的cpu使用率也比較高,每個Gif動畫增加了26%的cpu利用率(模擬器iphone 5,ios10.3)。
對于開源的引導頁類庫,我們以EAIntroView為例,它的實現原理實際上是在一個scrollView容器上,平鋪四個imageView和一個指式條,劃動時切換到上/下一個頁面。當使用Gif動畫時,實際上將同時播放四個gif,因此造成CPU使用率較高,真機測試iOS10.3,iphone 6,cpu使用率70%左右。
優化
由于引導頁的實現方式是將多個imageView同時放到scrollView上,造成幾個Gif動畫同時播放,CPU使用率較高。為了解決這個問題,現引入FLAnimatedImage庫。這個庫支持停止、播放動畫。當劃到某頁時,才會去播放當前頁的Gif動畫,這樣就降低了資源消耗情況,優化后cpu利用率降低到32%。
Gif實例
寫了一個Demo,基于EAIntroView,功能尚不完善,僅僅用于驗證實際效果。地址:https://github.com/superzcj/ZCJGifInIntroDemo
self.gifArr = [NSMutableArray new];
NSMutableArray *views = [NSMutableArray new];
for (int i=0; i<4; i++) {
NSString *imageName = [NSString stringWithFormat:@"guideImage_%d", i + 1];
NSURL *url1 = [[NSBundle mainBundle] URLForResource:imageName withExtension:@"gif"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:data1];
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] initWithFrame:self.view.bounds];
imageView.backgroundColor = [UIColor clearColor];
imageView.animatedImage = image;
UIView *bgView = [[UIView alloc] initWithFrame:self.view.bounds];
[bgView addSubview:imageView];
[views addObject:bgView];
[self.gifArr addObject:imageView];
}
代碼如上,首先從本地讀取Gif動畫圖片,生成FLAnimatedImage圖片對象,再傳遞給FLAnimatedImageView以顯示。為了在后面控制每個Gif對象的播放與停止,將Gif動畫容器放入gifArr數組中。
EAIntroPage *page1 = [EAIntroPage pageWithCustomView:views[0]];
EAIntroPage *page2 = [EAIntroPage pageWithCustomView:views[1]];
EAIntroPage *page3 = [EAIntroPage pageWithCustomView:views[2]];
EAIntroPage *page4 = [EAIntroPage pageWithCustomView:views[3]];
EAIntroView *intro = [[EAIntroView alloc] initWithFrame:self.view.bounds andPages:@[page1,page2,page3,page4]];
[intro.skipButton setTitle:@"跳過" forState:UIControlStateNormal];
[intro setDelegate:self];
intro.tapToNext = YES;
[intro showInView:self.view animateDuration:0.3];
創建四個引導頁頁面,將上面生成的頁面內容傳遞進來,最后將引導頁添加到頁面上。
- (void)intro:(EAIntroView *)introView pageAppeared:(EAIntroPage *)page withIndex:(NSUInteger)pageIndex {
NSLog(@"Current page index = %lu", (unsigned long)pageIndex);
for (FLAnimatedImageView *iv in self.gifArr) {
[iv stopAnimating];
}
FLAnimatedImageView *imageView = self.gifArr[pageIndex];
[imageView startAnimating];
}
滑動引導頁時,停止所有的Gif動畫,只播放新出現的當前頁動畫。
FLAnimatedImage
FLAnimatedImage是由Flipboard開源的iOS平臺上播放GIF動畫的一個優秀解決方案,在內存占用和播放體驗都有不錯的表現。它在Github上的Star有5461個,被Facebook、Dropbox等應用引用。
FLAnimatedImage的實現原理很簡單,只有兩個類,FLAnimatedImage負責解析GIF動畫數據,讀取Gif中的每一幀圖片,FLAnimatedImageView則展示FLAnimatedImage處理后的動畫數據,控制Gif動畫的播放、停止等。
FLAnimatedImage利用CGImageSource獲取圖像對象、圖片屬性信息等,調用CGImageSourceCopyProperties方法獲取到Gif動畫循環次數,調用CGImageSourceCreateImageAtIndex取得幀圖片,然后根據GIF圖的大小和緩存策略判斷需要緩存的單幀圖片數量,緩存起來。
FLAnimatedImageView是UIImageView的子類,完全兼容UIImageView的各個方法。它設置GIF動畫的封面幀圖片,當前幀索引,GIF動畫的循環播放次數,播放時間累加器,更新是否發起動畫的標志位,判斷是否啟動GIF動畫。
第三方庫動態引導頁
使用第三方的動態引導頁類庫,能大大提升開發效率。
JazzHands是一個動態引導頁類庫,它是基于關鍵幀的動畫框架, 可以用于手勢,滾動視圖,KVO或者ReactiveCocoa, 十分方便。它在Github上star數有6102,在引導頁類庫中最受歡迎。
官方提供了一個很酷炫的Demo,地址:https://github.com/IFTTT/JazzHands。
總結
Gif動畫 | 第三方庫(JazzHands) | 動畫 | |
---|---|---|---|
開發工作量 | 低 | 高 | 極高 |
維護工作量 | 低 | 高 | 極高 |
cpu利用率和內存占用 | 高(26%的cpu利用率) | 低(cpu使用率在10%) | 低 |
兼容性 | 支持iOS7,支持小屏幕 | 支持ios7,支持小屏幕 | 支持 |
適用性 | 僅支持單頁動畫 | 支持多種類型動畫 | 無限制 |