實現(xiàn)動畫方式深度解析(一) —— 播放GIF動畫(一)

版本記錄

版本號 時間
V1.0 2017.09.16

前言

app中好的炫的動畫可以讓用戶耳目一新牲蜀,為產(chǎn)品增色不少蚂子,關(guān)于動畫的實現(xiàn)我們可以用基本動畫、關(guān)鍵幀動畫截亦、序列幀動畫以及基于CoreGraphic的動畫等等肮疗,接下來這幾篇我就介紹下我可以想到的幾種動畫繪制方法戚扳。具體Demo示例已開源到Github —— 刀客傳奇

ios中實現(xiàn)動畫的幾種方式

  • GIF

    • 這個就很簡單了,讓UI給你個Gif圖族吻,你就直播播放就可以了帽借。具體播放可是使用UIWebView、UIImageView以及框架FLAnimatedImage
  • 序列幀動畫

    • 將動畫的每一幀都放在本地超歌,然后用UIImageView播放序列幀動畫砍艾。
  • 系統(tǒng)的框架CoreAnimation

    • 里面可以做關(guān)鍵幀動畫,基本動畫等等巍举。下面會給出CoreAnimation的框架結(jié)構(gòu)圖脆荷,關(guān)于CoreAnimation框架我會分一大塊去講解。
  • 系統(tǒng)自帶的UIView動畫

    • 直接在block里面實現(xiàn)位置大小改變等操作,并可設(shè)置動畫結(jié)束后的邏輯蜓谋,可做一些簡單的動畫梦皮。
  • 第三方框架比如說Lottie - ios

  • 第三方框架比如說Facebook Keyframes剑肯,

    • 關(guān)鍵幀是Facebook構(gòu)建的一個非常好的新庫。 然而观堂,關(guān)鍵幀不支持一些Lottie的功能让网,如遮罩,修剪路徑等等师痕。
  • CoreGraphic

    • 利用CoreGraphic和時間控制溃睹,可以自己自定義設(shè)計動畫,這種方式不是很好把握胰坟,但是還是可以實現(xiàn)的因篇。
CoreAnimation

上面已經(jīng)列出來了,我認(rèn)為很全的做動畫的幾種方式或者思考方法笔横,不足的或者疏漏的希望大家提醒我竞滓,我好補全。


播放GIF動畫

播放GIF動畫的方式有很多狠裹,下面我就主要介紹幾種方式虽界。首先準(zhǔn)備了點GiF素材,如下涛菠。

1. 利用WebView播放GIF動畫

利用系統(tǒng)自帶的WebView就可以加載數(shù)據(jù)播放動畫莉御。主要思路步驟如下:

  • 找到gif文件在bundle的地址路徑
  • 利用NSData的類方法,將gif數(shù)據(jù)類型改變
  • 利用UIWebView對象方法loadData:加載數(shù)據(jù)就可以播放了俗冻。

具體代碼如下所示:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    
    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, 0.0, 375, 667)];
    webView.scalesPageToFit = YES;
    webView.opaque = NO;
    [self.view addSubview:webView];
    
    //找到路徑文件
    NSString *pathStr = [[NSBundle mainBundle] pathForResource:@"gifAnimation.gif" ofType:nil];
    
    //將gif轉(zhuǎn)化為NSData數(shù)據(jù)
    NSData *gifData = [NSData dataWithContentsOfFile:pathStr];
    
    //將gifData給WebView進行播放
    [webView loadData:gifData MIMEType:@"image/gif" textEncodingName:nil baseURL:nil];
}

@end

下面看一下播放效果

可見可以正常播放礁叔,具體界面適配問題就不說了,能播放就可以迄薄。

2. 利用UIImageView和ImageIO框架播放

具體思路就是將gif轉(zhuǎn)化為多張靜態(tài)png圖片琅关,然后利用UIImageView播放。需要借助框架#import <ImageIO/ImageIO.h>里面的接口實現(xiàn)讥蔽。

下面我們就看一下代碼

#import "ViewController.h"
#import <ImageIO/ImageIO.h>

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //gif URL路徑
    NSURL *gifURL = [[NSBundle mainBundle] URLForResource:@"gifAnimation" withExtension:@"gif"];
    
    //gif轉(zhuǎn)圖片
    CGImageSourceRef gifSource = CGImageSourceCreateWithURL((CFURLRef)gifURL, NULL);
    
    //圖片個數(shù)
    size_t frameCount = CGImageSourceGetCount(gifSource);
    
    //將CGImage轉(zhuǎn)化為UIImage涣易,并存儲在數(shù)組里面
    NSMutableArray *frameArrM = [NSMutableArray array];
    for (size_t i = 0; i < frameCount; i ++) {
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
        UIImage *image = [UIImage imageWithCGImage:imageRef];
        [frameArrM addObject:image];
        CGImageRelease(imageRef);
    }
    
    //動畫顯示
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:imageView];
    imageView.animationImages = [frameArrM copy];
    imageView.animationDuration = 1/10;
    [imageView startAnimating];
}

@end

下面看一下效果驗證。

UIImageView播放是通過定時器來控制圖片模擬動畫的冶伞,它們控制的楨速是固定的新症。如果設(shè)置的模擬楨速跟gif本身的楨速相近的話倒沒什么,如果楨速相差過大就會產(chǎn)生卡頓或者快進的視覺效果响禽。

3. SDWebImage

這個網(wǎng)絡(luò)圖片加載框架徒爹,大家都很清楚了荚醒,和gif相關(guān)的類只有UIImage+GIF,它是UIImage的一個分類隆嗅。

看一下這個分類的接口

#import "SDWebImageCompat.h"

@interface UIImage (GIF)

/**
 *  Compatibility method - creates an animated UIImage from an NSData, it will only contain the 1st frame image
 */
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;

/**
 *  Checks if an UIImage instance is a GIF. Will use the `images` array
 */
- (BOOL)isGIF;

@end

這個接口只提供了兩個方法:

  • + (UIImage *)sd_animatedGIFWithData:(NSData *)data;界阁,這個方法只會返回第一幀。
  • - (BOOL)isGIF;判斷UIImage實例是否是Gif胖喳。

下面看一下具體實現(xiàn)

#import "UIImage+GIF.h"
#import <ImageIO/ImageIO.h>
#import "objc/runtime.h"
#import "NSImage+WebCache.h"

@implementation UIImage (GIF)

+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
    if (!data) {
        return nil;
    }

    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

    size_t count = CGImageSourceGetCount(source);

    UIImage *staticImage;

    if (count <= 1) {
        staticImage = [[UIImage alloc] initWithData:data];
    } else {
        // we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category.
        // this here is only code to allow drawing animated images as static ones
#if SD_WATCH
        CGFloat scale = 1;
        scale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
        CGFloat scale = 1;
        scale = [UIScreen mainScreen].scale;
#endif
        
        CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
#if SD_UIKIT || SD_WATCH
        UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
        staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f];
#elif SD_MAC
        staticImage = [[UIImage alloc] initWithCGImage:CGImage size:NSZeroSize];
#endif
        CGImageRelease(CGImage);
    }

    CFRelease(source);

    return staticImage;
}

- (BOOL)isGIF {
    return (self.images != nil);
}

@end

調(diào)用上面的接口只能返回第一幀泡躯。所以不可以的,我查了下資料禀晓,SDWebImage以前是可以的精续,但是后來更改了接口就不可以了坝锰。

下面我們就驗證這個問題粹懒,看一下代碼

#import "ViewController.h"
#import "SDWebImage/UIImage+GIF.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //找到路徑文件
    NSString *pathStr = [[NSBundle mainBundle] pathForResource:@"gifAnimation.gif" ofType:nil];
    
    //將gif轉(zhuǎn)化為NSData數(shù)據(jù)
    NSData *gifData = [NSData dataWithContentsOfFile:pathStr];
    
    UIImage *image = [UIImage sd_animatedGIFWithData:gifData];
    
    //顯示
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:imageView];
    imageView.image = image;
}

@end

運行起來就會發(fā)現(xiàn),只是一張靜態(tài)的圖片顷级,并不能播放GIF凫乖。為什么會這樣呢?

看一下UIImage+GIF.mcount > 1時給的提示:

//we will only retrieve the 1st frame. the full GIF support is available via the FLAnimatedImageView category.
// this here is only code to allow drawing animated images as static ones

意思就是讓我們使用FLAnimatedImageView這個框架和接口播放GIF弓颈。

所以帽芽,利用SDWebImage框架播放GIF是行不通的了。

4. FLAnimatedImage

FLAnimatedImage 是由Flipboard開源的iOS平臺上播放GIF動畫的一個優(yōu)秀解決方案翔冀,在內(nèi)存占用和播放體驗都有不錯的表現(xiàn)导街。

這里就簡單的提一下,詳細(xì)的說明放在下篇纤子,避免內(nèi)容混雜搬瑰,保持邏輯的清晰性,希望大家持續(xù)關(guān)注我控硼。

后記

未完泽论,待續(xù)~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市卡乾,隨后出現(xiàn)的幾起案子翼悴,更是在濱河造成了極大的恐慌,老刑警劉巖幔妨,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹦赎,死亡現(xiàn)場離奇詭異,居然都是意外死亡误堡,警方通過查閱死者的電腦和手機古话,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埂伦,“玉大人煞额,你說我怎么就攤上這事。” “怎么了膊毁?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵胀莹,是天一觀的道長。 經(jīng)常有香客問我婚温,道長描焰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任栅螟,我火速辦了婚禮荆秦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘力图。我一直安慰自己步绸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布吃媒。 她就那樣靜靜地躺著瓤介,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赘那。 梳的紋絲不亂的頭發(fā)上刑桑,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音募舟,去河邊找鬼祠斧。 笑死,一個胖子當(dāng)著我的面吹牛拱礁,可吹牛的內(nèi)容都是我干的琢锋。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼觅彰,長吁一口氣:“原來是場噩夢啊……” “哼吩蔑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起填抬,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤烛芬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后飒责,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赘娄,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年宏蛉,在試婚紗的時候發(fā)現(xiàn)自己被綠了遣臼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡拾并,死狀恐怖揍堰,靈堂內(nèi)的尸體忽然破棺而出鹏浅,到底是詐尸還是另有隱情,我是刑警寧澤屏歹,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布隐砸,位于F島的核電站,受9級特大地震影響蝙眶,放射性物質(zhì)發(fā)生泄漏季希。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一幽纷、第九天 我趴在偏房一處隱蔽的房頂上張望式塌。 院中可真熱鬧,春花似錦友浸、人聲如沸峰尝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽境析。三九已至囚枪,卻和暖如春派诬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背链沼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工默赂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人括勺。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓缆八,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疾捍。 傳聞我的和親對象是個殘疾皇子奈辰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容