import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class ProgressBar extends StatefulWidget { final String title; final int? value; final Color color; const ProgressBar({ super.key, required this.title, required this.value, required this.color, }); @override State createState() => _ProgressBarState(); } class _ProgressBarState extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; late Animation _progressAnimation; late Tween _valueTween; @override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 2), ); _setupAnimation(); _startAnimation(); } @override void didUpdateWidget(covariant ProgressBar oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.value != widget.value) { _setupAnimation(); _startAnimation(); } } /// 设置动画曲线和范围 void _setupAnimation() { if (widget.value == null) { _valueTween = Tween(begin: 0.0, end: 1.0); } else { _valueTween = Tween( begin: 0, end: _getTargetProgress(), ); } _progressAnimation = _valueTween.animate( CurvedAnimation(parent: _animationController, curve: Curves.easeOut), ); } double _getTargetProgress() { return (widget.value ?? 0) / 100.0; } void _startAnimation() { _animationController.stop(); if (widget.value == null) { _animationController.repeat(); } else { _animationController ..reset() ..forward(); } } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final bool isLoading = widget.value == null; return Row( children: [ Text(widget.title), SizedBox(width: 3.w), Expanded( child: Stack( children: [ // 背景条 Container( height: 11.h, decoration: BoxDecoration( color: widget.color.withOpacity(0.3), borderRadius: BorderRadius.circular(53.r), ), ), // 动画进度条 AnimatedBuilder( animation: _progressAnimation, builder: (_, __) { final double progress = _progressAnimation.value; return FractionallySizedBox( widthFactor: progress.clamp(0.0, 1.0), child: Container( height: 11.h, decoration: BoxDecoration( color: widget.color, borderRadius: BorderRadius.circular(53.r), ), ), ); }, ), // 中间文字 Positioned.fill( child: Center( child: Text( isLoading ? "加载中..." : "${(widget.value ?? 0).clamp(0, 100)}%", style: TextStyle( color: Colors.white, fontSize: 7.sp, fontWeight: FontWeight.w500, shadows: [ Shadow( color: Colors.black.withOpacity(0.6), offset: Offset(1, 1), blurRadius: 3.r, ), ], ), ), ), ), ], ), ), ], ); } }