You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Flare动画作为图片占位符并实现淡入切换效果

用Flare动画作为网络图片的淡入占位符

你说得对,FadeInImage的placeholder参数只能接收ImageProvider类型,没法直接传入FlareActor这种Widget。不过我们可以自己实现一套类似的逻辑,用Flare动画做占位,等图片加载完成后淡入切换,下面给你两种可行的方案:

方案一:用AnimatedSwitcher + FutureBuilder

这种方法利用FutureBuilder监听图片加载状态,配合AnimatedSwitcher实现平滑的淡入切换效果:

首先,先写一个工具函数来监听网络图片的加载完成事件:

Future<void> _loadNetworkImage(String imageUrl) {
  final completer = Completer<void>();
  final networkImage = NetworkImage(imageUrl);
  
  networkImage.resolve(const ImageConfiguration()).addListener(
    ImageStreamListener((info, isSynchronous) {
      // 跳过同步加载的情况,确保是异步加载完成才触发
      if (!isSynchronous) {
        completer.complete();
      }
    }),
    onError: (error, stackTrace) {
      // 处理图片加载失败的情况
      completer.completeError(error, stackTrace);
    },
  );
  
  return completer.future;
}

然后在Widget的build方法里使用:

@override
Widget build(BuildContext context) {
  return FutureBuilder<void>(
    future: _loadNetworkImage(product.imageUrl),
    builder: (context, snapshot) {
      return AnimatedSwitcher(
        // 淡入动画的时长,可根据需求调整
        duration: const Duration(milliseconds: 300),
        // 切换时的动画曲线
        switchInCurve: Curves.easeInOut,
        child: () {
          if (snapshot.hasError) {
            // 图片加载失败时,继续显示Flare动画(也可以换成错误提示Widget)
            return FlareActor(
              "assets/images/image_placeholder.flr",
              animation: "Untitled",
              key: const ValueKey('flare-error'),
            );
          }
          
          return snapshot.connectionState == ConnectionState.done
              // 图片加载完成,显示网络图片
              ? Image.network(
                  product.imageUrl,
                  fit: BoxFit.cover,
                  key: const ValueKey('loaded-image'),
                )
              // 图片加载中,显示Flare动画
              : FlareActor(
                  "assets/images/image_placeholder.flr",
                  animation: "Untitled",
                  key: const ValueKey('flare-loading'),
                );
        }(),
      );
    },
  );
}

方案二:用Stack + AnimatedOpacity

这种方法更直接,把Flare动画放在底层,网络图片放在上层,通过AnimatedOpacity控制图片的透明度来实现淡入效果:

首先在Widget里添加一个状态变量,标记图片是否加载完成:

bool _isImageLoaded = false;

@override
void initState() {
  super.initState();
  // 初始化时就开始监听图片加载
  _startImageLoading();
}

void _startImageLoading() {
  final networkImage = NetworkImage(product.imageUrl);
  
  networkImage.resolve(const ImageConfiguration()).addListener(
    ImageStreamListener((info, isSynchronous) {
      if (!isSynchronous) {
        setState(() {
          _isImageLoaded = true;
        });
      }
    }),
    onError: (error, stackTrace) {
      // 加载失败可以在这里做额外处理,比如提示用户
      debugPrint('图片加载失败:$error');
    },
  );
}

然后在build方法里用Stack叠加两个Widget:

@override
Widget build(BuildContext context) {
  return Stack(
    fit: StackFit.expand,
    children: [
      // 底层的Flare占位动画
      FlareActor(
        "assets/images/image_placeholder.flr",
        animation: "Untitled",
        fit: BoxFit.cover,
      ),
      // 上层的网络图片,通过透明度动画实现淡入
      AnimatedOpacity(
        opacity: _isImageLoaded ? 1.0 : 0.0,
        duration: const Duration(milliseconds: 300),
        child: Image.network(
          product.imageUrl,
          fit: BoxFit.cover,
          // 图片加载失败时隐藏图片,继续显示Flare动画(可选)
          errorBuilder: (context, error, stackTrace) {
            return const SizedBox.shrink();
          },
        ),
      ),
    ],
  );
}

这两种方案都能实现你想要的效果:加载时显示Flare动画,图片加载完成后平滑淡入替换。如果需要更复杂的动画,还可以自定义AnimatedSwitcher的transitionBuilder参数来调整切换效果。

内容的提问来源于stack exchange,提问作者Asad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 10:02:37