详解iOS如何让Lottie使用网络资源做动画的实现
QYizhong 人气:0背景
手上有需求需要使用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 = @"https://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是os.xxx.cn/lottie/anim… ,那么需要给LOTComposition的baseURL设置为os.xxx.cn/lottie/anim… 。
3. 初始化LOTAnimationView
最后只需要请求资源并传给LOTAnimationView即可。
- (LOTAnimationView *)animationView { if (!_animationView) { //注意,如果想先初始化view再请求资源,不要使用new或者init来初始化 _animationView = [[LOTAnimationView alloc] initWithFrame:CGRectZero]; _animationView.animationDelegate = self; NSURL *url = [NSURL URLWithString:@"https://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; }
加载全部内容