iOS如何讓Lottie使用網路資源做動畫

語言: CN / TW / HK

背景

手上有需求需要使用CDN資源來讓Lottie做動畫,但由於動畫需要載入圖片,而Lottie提供的初始化介面只能載入json配置,Github上的issues也沒人回答,因此特地寫下本文記錄一下方案。

為了實現這個功能還把Lottie看了一遍也是醉了。。。

方案

首先需要明確的一個點是如果你的Lottie資源帶圖片,那麼直接使用LOTAnimationView的initWithContentsOfURL:方法是無法自動載入圖片資源的。因為載入圖片需要為LOTComposition設定baseURL,但通過url初始化animatonView時,由於json配置需要非同步載入,所以該view的sceneModel為空,你無法直接設定,而view內部又沒有載入完成的回撥,因此只能通過監聽sceneModel設定或者生成一個sceneModel傳入這兩種方式來實現Lottie圖片資源載入。

以下介紹實現方式。

1. 實現LOTAnimationDelegate代理

首先需要實現LOTAnimationView的圖片請求代理方法。Lottie內部不會自行請求圖片,而是通過代理方法的形式將圖片請求拋到外部實現。

``` - (void)animationView:(LOTAnimationView )animationView fetchResourceWithURL:(NSURL )url completionHandler:(LOTResourceCompletionHandler)completionHandler {     [CDNService requestLottieImageWithURL:url completion:^(UIImage * _Nullable image, NSError * _Nullable error) {         if (completionHandler) {             completionHandler(image, error);         }     }];

} ```

2. 生成LOTComposition

其次,由於外部業務無法直接感知LOTAnimationView內部生成的LOTComposition的時機,因此可以選擇自己生成它,並設定baseURL。

+ (void)requestLottieModelWithURL:(NSURL *)url completion:(void(^)(LOTComposition * _Nullable sceneModel,  NSError * _Nullable error))completion {     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {         NSData *animationData = [NSData dataWithContentsOfURL:url];         if (!animationData) {             return;         }         NSError *error;         NSDictionary *animationJSON = [NSJSONSerialization JSONObjectWithData:animationData options:0 error:&error];         if (error || !animationJSON) {             if (completion) {                 completion(nil, error);             }             return;         }         LOTComposition *model = [[LOTComposition alloc] initWithJSON:animationJSON withAssetBundle:[NSBundle mainBundle]];         dispatch_async(dispatch_get_main_queue(), ^(void) {             [[LOTAnimationCache sharedCache] addAnimation:model forKey:url.absoluteString]; //注意,這裡的baseURL是你的請求path,需要根據你的業務情況自行設定             model.baseURL = @"http://os.xxx.cn/lottie/animation/";             model.cacheKey = url.absoluteString;             if (completion) {                 completion(model, nil);             }         });     }); }

需要注意的是LOTComposition的baseURL設定,不僅需要檢視Lottie的json配置檔案,還需要關注服務端儲存Lottie檔案的路徑。

假設你有一個叫animation的Lottie資源,那麼請先開啟配置json觀察assets.u的值。這裡假設assets.u為"images/",則你需要在服務端儲存的檔案結構如下:

- animation - data.json - images - img_0.png - img_1.png

此時,如果json的請求url是http://os.xxx.cn/lottie/animation/data.json ,那麼需要給LOTComposition的baseURL設定為http://os.xxx.cn/lottie/animation/ 。

3. 初始化LOTAnimationView

最後只需要請求資源並傳給LOTAnimationView即可。

- (LOTAnimationView *)animationView { if (!_animationView) { //注意,如果想先初始化view再請求資源,不要使用new或者init來初始化 _animationView = [[LOTAnimationView alloc] initWithFrame:CGRectZero]; _animationView.animationDelegate = self; NSURL *url = [NSURL URLWithString:@"http://os.xxx.cn/lottie/animation/data.json"]; //請求json配置,生成LOTComposition後傳給view @weakify(self); [CCDNService requestLottieModelWithURL:url completion:^(LOTComposition * _Nullable sceneModel, NSError * _Nullable error) { @strongify(self); self.animationView.sceneModel = sceneModel; }]; } return _animationView; }