Is there a way to precache Lottie animations in flutter?
Asked Answered
R

1

7

I have a lottie animation that I'm using as a loading screen:

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:lottie/lottie.dart';

class Loading extends StatelessWidget {
  final String loadingText;
  Loading({this.loadingText});

  Widget build(BuildContext context) {
    return Container(
      width: double.infinity,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (loadingText != null) _buildLoadingText(loadingText),
          _buildAnimation(),
        ],
      ),
    );
  }

  Widget _buildLoadingText(String text) {
    return Text(
      loadingText,
      style: GoogleFonts.poppins(
          textStyle:
              TextStyle(fontWeight: FontWeight.w500, color: Colors.black)),
    );
  }

  Widget _buildAnimation() {
    return Lottie.asset('assets/lottie/heartbeat_loading.json',
        width: 300, repeat: true, animate: true);
  }
}

And I'm using it like this for when my app initially loads:

_determineHome() {
    return StreamBuilder(
      stream: AppBlocContainer().authenticationBloc().loggedIn,
      builder: (context, AsyncSnapshot<AuthenticationStatus> snapshot) {
        // return Loading();
        return AnimatedSwitcher(
            duration: Duration(seconds: 2),
            child: !snapshot.hasData
                ? Loading(
                    loadingText: 'Loading...',
                  )
                : _buildSecondChild(snapshot.data));
      },
    );

This works, except that the lottie animation is being loaded maybe a second or two too late, which by the time the lottie asset loads, it's too late and the page has already transitioned.

I was wondering since I did was able to precache my SVG images in my main() by doing this:

    Future.wait([
      precachePicture(
        ExactAssetPicture(
            SvgPicture.svgStringDecoder, 'assets/svg/login.svg'),
        null,
      ),
      precachePicture(
        ExactAssetPicture(
            SvgPicture.svgStringDecoder, 'assets/svg/logo.svg'),
        null,
      ),
      precachePicture(
        ExactAssetPicture(
            SvgPicture.svgStringDecoder, 'assets/svg/signup_panel_1.svg'),
        null,
      )
    ]);

Would I be able to do the same thing with lottie?

Rationalize answered 3/10, 2021 at 17:3 Comment(0)
I
10

what I found is that lottie package in flutter, itself got a built in auto cache.(want it or not it will cache the animation into ram)

method A(own made): so you basically need to call Lottie.asset('assets/Logo.json') once and the second time you will be able to load it without delay by calling Lottie.asset('assets/Logo.json') again because it was cached at the first time. so this can be used as a cheat cache method, for example you can load it first in splash screen like below: either by wrapping with a SizedBox and giving 0 height/width or using Visibility widget with visible property of false but maintainState to true, so its not visible but still will be in widget tree and load into ram.

        Visibility(
          visible: false,
          maintainSize: false,
          maintainState: true,
          maintainAnimation: false,
          maintainInteractivity: false,
          child: Row(
            children: [
               Lottie.asset('assets/Logo.json'),
            ],
          ),
        ),
            

next time where you need just call Lottie.asset('assets/Logo.json') and it will load without delay.

method B: this is mentioned by a guy called Pante on github.

class LottieCache {

  final Map<String, LottieComposition> _compositions = {};

  /// Caches the given [LottieAsset]s.

  Future<void> add(String assetName) async {
      _compositions[assetName] = await AssetLottie(assetName).load();
  }
  
  Widget load(String assetName, Widget fallback) {
    final composition = _compositions[assetName];
    return composition != null ? Lottie(composition: composition) : fallback;
  }

}

there are 2 ways here: 1)use AssetLottie(assetName).load() method; provide the LottieCache object in order to access its load method where ever you need. 2)completly neglect load method and the composition way(you can comment the load method);because AssetLottie(assetName).load() loads the animation into ram just as the same as Lottie.asset('assets/Logo.json') so just calling its add method will load animation into ram and you can use it without delay next time where you need.

method C: this is a custom loading method mentioned in lottie documentation for flutter.

class _MyWidgetState extends State<MyWidget> {
  late final Future<LottieComposition> _composition;

  @override
  void initState() {
    super.initState();

    _composition = _loadComposition();
  }

  Future<LottieComposition> _loadComposition() async {
    var assetData = await rootBundle.load('assets/LottieLogo1.json');
    return await LottieComposition.fromByteData(assetData);
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<LottieComposition>(
      future: _composition,
      builder: (context, snapshot) {
        var composition = snapshot.data;
        if (composition != null) {
          return Lottie(composition: composition);
        } else {
          return const Center(child: CircularProgressIndicator());
        }
      },
    );
  }
}
Inger answered 20/5, 2022 at 22:35 Comment(1)
Method 3rd is the best! even it is recommened by original teamKnew

© 2022 - 2024 — McMap. All rights reserved.