如何将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
相关产品推荐
相关产品推荐

