iOS에서 Lottie가 애니메이션에 네트워크 리소스를 사용하도록 허용하는 방법

배경

Lottie가 애니메이션을 하게 하려면 CDN 리소스를 사용해야 하는데 애니메이션은 이미지를 불러와야 하기 때문에 Lottie에서 제공하는 초기화 인터페이스는 json 구성만 불러올 수 있고 Github에서도 문제를 해결한 사람이 없어서 이렇게 글을 작성하게 되었습니다. 솔루션을 기록합니다.

이 기능을 이루기 위해 로티를 다시 보고 취하기까지 했다. . .

계획

첫 번째로 분명히 해야 할 점은 Lottie 리소스에 사진이 있는 경우 LOTTanimationView의 initWithContentsOfURL: 메서드를 직접 사용하여 사진 리소스를 자동으로 로드할 수 없다는 것입니다. 사진을 불러오려면 LOTComposition에 baseURL을 설정해야 하지만 url을 통해 animatonView를 초기화할 때 json 구성을 비동기적으로 불러와야 하므로 view의 sceneModel이 비어있어 직접 설정할 수 없으며 내부에 불러오기 완료를 위한 콜백이 없습니다. 따라서 SceneModel 설정에 듣기만 전달하거나 Lottie 이미지 리소스 로드를 실현하기 위해 이 두 가지 방법으로 전달할 sceneModel을 생성할 수 있습니다.

구현은 아래에 설명되어 있습니다.

1. Lottie 라이브러리용 LOTAnimationDelegate 에이전트 추가

먼저 LOOTAnimationView의 이미지 요청 프록시 메서드를 구현해야 합니다. Lottie는 내부적으로 이미지를 요청하지 않으며, LOTLayerContainer의 _setImageForAsset: 메서드에서 프록시 메서드를 사용하여 이미지 요청을 외부로 던져 구현합니다. 그런 다음 사진을 가져와서 self.wrapperLayer.contents에 할당합니다. 예제는 다음과 같습니다.

- (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. LOTComposition 생성

둘째, 외부 사업자는 LOOTAnimationView 내부에서 생성되는 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是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;
}
复制代码

추천

출처juejin.im/post/7195449060201857084