Flutter中为线性进度指示器添加移动光效覆盖层的方法
解决LinearPercentIndicator进度条光效超出末端的问题
问题出在你把Shimmer.fromColors直接包裹了整个LinearPercentIndicator,导致光效作用于整个指示器容器,而非仅已填充的进度区域。下面是两种可行的解决方案:
方案一:利用LinearPercentIndicator的progressWidget参数
直接自定义进度区域的Widget,将Shimmer限制在进度范围内,这是最简洁的实现方式:
ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(10)), child: LinearPercentIndicator( padding: EdgeInsets.zero, width: 353.w, animation: true, lineHeight: 58.w, animationDuration: 1500, percent: percentage > 1 ? 1 : (percentage < 0 ? 0 : percentage), linearStrokeCap: LinearStrokeCap.roundAll, backgroundColor: kCasesTileBGColor, // 自定义进度区域为带Shimmer的Widget,无需再设置progressColor progressWidget: Shimmer.fromColors( baseColor: kBlue.withOpacity(0.9), highlightColor: Colors.white, // 白色高光渐变,可按需调整透明度 loop: true, child: Container( width: double.infinity, height: double.infinity, decoration: BoxDecoration( color: kBlue.withOpacity(0.9), borderRadius: BorderRadius.circular(10), ), ), ), ), )
方案二:用Stack+ClipRect手动控制Shimmer范围
通过Stack将Shimmer叠加在进度条上方,并用自定义裁剪器限制Shimmer的宽度为进度条的实际填充宽度,适合需要更复杂光效的场景:
ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(10)), child: Stack( children: [ // 原进度条(基础样式) LinearPercentIndicator( padding: EdgeInsets.zero, width: 353.w, animation: true, lineHeight: 58.w, animationDuration: 1500, percent: percentage > 1 ? 1 : (percentage < 0 ? 0 : percentage), linearStrokeCap: LinearStrokeCap.roundAll, backgroundColor: kCasesTileBGColor, progressColor: kBlue.withOpacity(0.9), ), // 叠加的Shimmer光效,用ClipRect限制范围 AnimatedBuilder( animation: _animationController, builder: (context, child) { final currentPercent = percentage > 1 ? 1 : (percentage < 0 ? 0 : percentage); return ClipRect( clipper: _ProgressClipper(percent: currentPercent), child: Shimmer.fromColors( baseColor: Colors.transparent, highlightColor: Colors.white.withOpacity(0.6), loop: true, child: Container( width: 353.w, height: 58.w, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ Colors.transparent, Colors.white.withOpacity(0.8), Colors.transparent, ], ), ), ), ), ); }, ), ], ), ) // 自定义裁剪器,限制Shimmer仅显示在进度范围内 class _ProgressClipper extends CustomClipper<Rect> { final double percent; _ProgressClipper({required this.percent}); @override Rect getClip(Size size) { return Rect.fromLTWH(0, 0, size.width * percent, size.height); } @override bool shouldReclip(covariant _ProgressClipper oldClipper) { return oldClipper.percent != percent; } }
方案二补充说明
需要在State类中初始化并管理AnimationController,确保与进度条动画同步:
late AnimationController _animationController; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 1500), vsync: this, )..forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); }
通用注意事项
- 方案一优先推荐,无需额外维护控制器,代码更简洁
- 高光颜色的透明度可根据视觉需求调整,避免光效过于刺眼
- 若需要圆角光效,确保Shimmer容器的圆角与进度条一致
内容的提问来源于stack exchange,提问作者sigma lab
相关产品推荐
相关产品推荐

