有没有办法在 flutter 中预缓存 Lottie 动画?

Spa*_*000 6 dart flutter lottie

我有一个 Lottie 动画,用作加载屏幕:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

当我的应用程序最初加载时,我会这样使用它:

_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));
      },
    );
Run Code Online (Sandbox Code Playgroud)

这是可行的,除了 Lottie 动画加载可能晚了一两秒,当 Lottie 资源加载时,已经太晚了,页面已经转换了。

我想知道我是否能够main()通过这样做来预先缓存我的 SVG 图像:

    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,
      )
    ]);
Run Code Online (Sandbox Code Playgroud)

我能对洛蒂做同样的事情吗?

ram*_*ami 6

我发现flutter中的lottie包本身有一个内置的自动缓存。(无论是否想要它都会将动画缓存到内存中)

方法A(自己制作):所以你基本上需要调用Lottie.asset('assets/Logo.json')一次,第二次你就可以通过调用Lottie.asset('assets/Logo.json')来毫不延迟地加载它。 json') 再次,因为它是第一次缓存。所以这可以用作作弊缓存方法,例如,您可以首先在启动屏幕中加载它,如下所示:通过使用 SizedBox 包装并给出 0 高度/宽度或使用可见性小部件,其可见属性为 false 但 keepState 为 true,所以它不可见,但仍然会在小部件树中并加载到内存中。

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

下次您需要时只需调用 Lottie.asset('assets/Logo.json') 即可立即加载。

方法B:这是github上一个叫Pante的人提到的。

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;
  }

}
Run Code Online (Sandbox Code Playgroud)

这里有两种方法:1)使用AssetLottie(assetName).load()方法;提供 LottieCache 对象,以便在需要时访问其加载方法。2)完全忽略load方法和合成方式(可以注释掉load方法);因为AssetLottie(assetName).load()将动画加载到ram中,就像Lottie.asset('assets/Logo.json')一样因此,只需调用其 add 方法即可将动画加载到 ram 中,您可以在下次需要时立即使用它。

方法C:这是lottie文档中提到的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());
        }
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)