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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:55:33