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

如何在Flutter中创建带闪光效果和百分比的可定制动画进度条?

可复用的Flutter动画进度条组件(带闪光效果)

当然有可复用的实现方式,直接封装成一个独立的StatefulWidget就能满足你所有需求,下面是完整的可复用代码,附带详细的使用说明:

完整组件代码

import 'package:flutter/material.dart';

class AnimatedProgressBar extends StatefulWidget {
  final double progress; // 范围 0.0 - 1.0
  final Color backgroundColor;
  final Color progressColor;
  final bool showShimmer;
  final Duration animationDuration;
  final TextStyle? percentageTextStyle;

  const AnimatedProgressBar({
    super.key,
    required this.progress,
    this.backgroundColor = Colors.grey[200]!,
    this.progressColor = Colors.blue,
    this.showShimmer = false,
    this.animationDuration = const Duration(milliseconds: 500),
    this.percentageTextStyle,
  }) : assert(progress >= 0.0 && progress <= 1.0, "进度值必须在0-1之间");

  @override
  State<AnimatedProgressBar> createState() => _AnimatedProgressBarState();
}

class _AnimatedProgressBarState extends State<AnimatedProgressBar> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _progressAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: widget.animationDuration,
      vsync: this,
    );
    // 初始化动画,从0开始到初始进度值
    _progressAnimation = Tween<double>(begin: 0.0, end: widget.progress).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
    );
    _controller.forward();
  }

  @override
  void didUpdateWidget(covariant AnimatedProgressBar oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 进度变化时,重新设置动画并播放
    if (oldWidget.progress != widget.progress) {
      _progressAnimation = Tween<double>(begin: _progressAnimation.value, end: widget.progress).animate(
        CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
      );
      _controller.reset();
      _controller.forward();
    }
  }

  @override
  void dispose() {
    // 及时销毁控制器,避免内存泄漏
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        // 顶部百分比文本
        Text(
          '${(_progressAnimation.value * 100).round()}%',
          style: widget.percentageTextStyle ?? TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w600,
            color: widget.progressColor,
          ),
        ),
        const SizedBox(height: 8),
        // 进度条容器
        Container(
          height: 12,
          width: double.infinity,
          decoration: BoxDecoration(
            color: widget.backgroundColor,
            borderRadius: BorderRadius.circular(6),
          ),
          clipBehavior: Clip.hardEdge,
          child: AnimatedBuilder(
            animation: _progressAnimation,
            builder: (context, child) {
              Widget progressBar = FractionallySizedBox(
                widthFactor: _progressAnimation.value,
                child: Container(color: widget.progressColor),
              );

              // 如果开启闪光效果,用ShaderMask添加渐变闪光
              if (widget.showShimmer) {
                progressBar = ShaderMask(
                  shaderCallback: (bounds) => LinearGradient(
                    colors: [
                      widget.progressColor,
                      Colors.white.withOpacity(0.5),
                      widget.progressColor,
                    ],
                    stops: const [0.0, 0.5, 1.0],
                    begin: Alignment.centerLeft,
                    end: Alignment.centerRight,
                  ).createShader(bounds),
                  blendMode: BlendMode.srcATop,
                  child: progressBar,
                );
              }

              return progressBar;
            },
          ),
        ),
      ],
    );
  }
}

使用示例

在你的页面中直接调用这个组件即可,下面是一个简单的演示:

class ProgressDemoPage extends StatefulWidget {
  const ProgressDemoPage({super.key});

  @override
  State<ProgressDemoPage> createState() => _ProgressDemoPageState();
}

class _ProgressDemoPageState extends State<ProgressDemoPage> {
  double _currentProgress = 0.3;

  void _updateProgress() {
    setState(() {
      _currentProgress = (_currentProgress + 0.2).clamp(0.0, 1.0);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('进度条演示')),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            // 带闪光效果的进度条
            AnimatedProgressBar(
              progress: _currentProgress,
              showShimmer: true,
              progressColor: Colors.green,
              backgroundColor: Colors.grey[300]!,
            ),
            const SizedBox(height: 40),
            // 不带闪光效果的进度条
            AnimatedProgressBar(
              progress: _currentProgress,
              showShimmer: false,
              progressColor: Colors.orange,
              percentageTextStyle: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
                color: Colors.orange,
              ),
            ),
            const SizedBox(height: 40),
            ElevatedButton(
              onPressed: _updateProgress,
              child: const Text('更新进度'),
            ),
          ],
        ),
      ),
    );
  }
}

核心特性说明

  • 平滑动画过渡:每次进度更新时,会从当前进度值平滑过渡到新值,动画曲线和时长都可配置
  • 可选闪光效果:通过showShimmer参数一键开关,用ShaderMask实现高效的渐变闪光效果
  • 高度自定义:支持配置背景色、进度色、百分比文本样式、动画时长等
  • 内存安全:正确实现了dispose方法销毁动画控制器,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 00:06:06