Flutter中Shimmer加载效果在iOS端失效,如何解决?
问题描述
我按照Flutter官方文档实现了ShimmerLoading组件,代码如下:
import 'package:flutter/widgets.dart'; const _shimmerGradient = LinearGradient( colors: [ Color(0xFFEBEBF4), Color(0xFFF00000), Color(0xFFEBEBF4), ], stops: [ 0.1, 0.3, 0.4, ], begin: Alignment(-1.0, -0.3), end: Alignment(1.0, 0.3), tileMode: TileMode.clamp, ); class ShimmerLoading extends StatefulWidget { const ShimmerLoading({ super.key, required this.isLoading, required this.child, }); final bool isLoading; final Widget child; @override State<ShimmerLoading> createState() => _ShimmerLoadingState(); } class _ShimmerLoadingState extends State<ShimmerLoading> { @override Widget build(BuildContext context) { if (!widget.isLoading) { return widget.child; } return ShaderMask( blendMode: BlendMode.srcATop, shaderCallback: (bounds) { return _shimmerGradient.createShader(bounds); }, child: widget.child, ); } }
测试页面集成代码:
// test_screen.dart class _TestScreenState extends BaseConsumerState<TestScreen> { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // 其他组件 ShimmerLoading( isLoading: true, child: Container( width: 200, height: 50, color: Colors.red, ), ), // 其他组件 ], ), ), ); } }
该效果在Android模拟器正常工作,但iOS端显示异常(呈现黑色方块),如何确保其在iOS真机上正常运行?
解决方案
iOS端出现黑色方块的核心原因是BlendMode.srcATop的跨平台渲染兼容性问题,结合颜色配置调整即可修复:
- 替换混合模式
将BlendMode.srcATop改为BlendMode.modulate,该模式在iOS和Android平台的渲染表现更统一:
return ShaderMask( blendMode: BlendMode.modulate, // 修改此处 shaderCallback: (bounds) { return _shimmerGradient.createShader(bounds); }, child: widget.child, );
- 调整梯度颜色(可选)
若修改混合模式后效果仍不理想,可调整梯度颜色的透明度,确保渐变过渡自然:
const _shimmerGradient = LinearGradient( colors: [ Color(0xFFEBEBF4), Color(0x80FF0000), // 改为半透明红色 Color(0xFFEBEBF4), ], stops: [ 0.1, 0.3, 0.4, ], begin: Alignment(-1.0, -0.3), end: Alignment(1.0, 0.3), tileMode: TileMode.clamp, );
- 补全动画逻辑(贴合标准Shimmer效果)
原代码缺少官方文档中的动画部分,添加动画不仅能实现闪烁效果,也能避免部分平台渲染异常:
class _ShimmerLoadingState extends State<ShimmerLoading> with SingleTickerProviderStateMixin { late AnimationController _animationController; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 1500), )..repeat(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { if (!widget.isLoading) { return widget.child; } return ShaderMask( blendMode: BlendMode.modulate, shaderCallback: (bounds) { return _shimmerGradient.createShader( bounds.shift(Offset(_animationController.value * bounds.width, 0)), ); }, child: widget.child, ); } }
内容的提问来源于stack exchange,提问作者Unemploy
相关产品推荐
相关产品推荐

