import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; 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: Duration(seconds: 1), ); _valueTween = Tween(begin: 0.0, end: _getTargetProgress()); _progressAnimation = _valueTween.animate( CurvedAnimation(parent: _animationController, curve: Curves.easeOut), ); _startAnimation(); } @override void didUpdateWidget(covariant ProgressBar oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.value != widget.value) { _valueTween = Tween( begin: _progressAnimation.value, end: _getTargetProgress(), ); _progressAnimation = _valueTween.animate( CurvedAnimation(parent: _animationController, curve: Curves.easeOut), ); _startAnimation(); } } double _getTargetProgress() { return (widget.value ?? 0) / 100.0; } void _startAnimation() { if (widget.value == null) { _animationController.repeat(); // 加载中,持续动画 } else { _animationController ..reset() ..forward(); // 有值,从 0 -> value 动画 } } @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.withValues(alpha: 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.withValues(alpha: 0.6), offset: Offset(1, 1), blurRadius: 3.r, ), ], ), ), ), ), ], ), ), ], ); } }