fundo
Existe a necessidade de usar recursos CDN para deixar Lottie fazer animações, mas como as animações precisam carregar imagens, a interface de inicialização fornecida por Lottie só pode carregar configurações json e ninguém respondeu aos problemas no Github, então escrevi este artigo para registre a solução.
Para conseguir essa função, até assisti Lottie novamente e estava bêbado. . .
plano
O primeiro ponto que precisa ser esclarecido é que, se o recurso Lottie tiver imagens, o uso direto do método initWithContentsOfURL: de LOTAnimationView não poderá carregar automaticamente o recurso de imagem. Como o carregamento de imagens precisa definir baseURL para LOTComposition, mas ao inicializar animatonView por meio de url, como a configuração json precisa ser carregada de forma assíncrona, o sceneModel da exibição está vazio, você não pode defini-lo diretamente e não há retorno de chamada para conclusão do carregamento dentro a exibição, portanto, você só pode passar as configurações de Listen to sceneModel ou gerar um sceneModel para passar dessas duas maneiras para realizar o carregamento do recurso de imagem Lottie.
A implementação é descrita a seguir.
1. Adicione o agente LOTAnimationDelegate para a biblioteca Lottie
Primeiro, você precisa implementar o método de proxy de solicitação de imagem de LOTAnimationView. Lottie não solicita imagens internamente e pode usar o método proxy no método _setImageForAsset: de LOTLayerContainer para enviar a solicitação de imagem para fora para implementação. Em seguida, obtenha a imagem e atribua-a a self.wrapperLayer.contents, o exemplo é o seguinte.
- (void)_setImageForAsset:(LOTAsset *)asset {
...
[delegate animationView:asset.animationView fetchResourceWithURL:url completionHandler:^(UIImage * _Nullable image, NSError * _Nullable error) {
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
self.wrapperLayer.contents = (__bridge id _Nullable)(image.CGImage);
});
}
}];
...
}
- (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. Gerar LOTComposition
Em segundo lugar, como o negócio externo não pode perceber diretamente o tempo do LOTComposition gerado dentro do LOTAnimationView, ele pode optar por gerá-lo sozinho e definir o 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);
}
});
});
}
复制代码
Deve-se observar que a configuração baseURL de LOTComposition não precisa apenas visualizar o arquivo de configuração json de Lottie, mas também precisa prestar atenção ao caminho onde o servidor armazena os arquivos Lottie.
假设你有一个叫animation的Lottie资源,那么请先打开配置json观察assets.u的值。这里假设assets.u为"images/",则你需要在服务端存储的文件结构如下:
- animation
- data.json
- images
- img_0.png
- img_1.png
复制代码
此时,如果json的请求url是https://os.xxx.cn/lottie/animation/data.json
,那么需要给LOTComposition的baseURL设置为https://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:@"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;
}
复制代码