import 'package:flutter/material.dart'; /// 简单的加载动画组件,替代有问题的flutter_spinkit class KRSimpleLoading extends StatefulWidget { final Color? color; final double size; final Duration duration; const KRSimpleLoading({ super.key, this.color, this.size = 40.0, this.duration = const Duration(milliseconds: 1000), }); @override State createState() => _KRSimpleLoadingState(); } class _KRSimpleLoadingState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: widget.duration, vsync: this, ); _animation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _controller, curve: Curves.easeInOut, )); _controller.repeat(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.rotate( angle: _animation.value * 2 * 3.14159, child: Container( width: widget.size, height: widget.size, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: widget.color ?? Theme.of(context).primaryColor, width: 2.0, ), ), child: Padding( padding: const EdgeInsets.all(2.0), child: CircularProgressIndicator( strokeWidth: 2.0, valueColor: AlwaysStoppedAnimation( widget.color ?? Theme.of(context).primaryColor, ), ), ), ), ); }, ); } } /// 脉冲加载动画 class KRSimplePulse extends StatefulWidget { final Color? color; final double size; final Duration duration; const KRSimplePulse({ super.key, this.color, this.size = 40.0, this.duration = const Duration(milliseconds: 1500), }); @override State createState() => _KRSimplePulseState(); } class _KRSimplePulseState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; @override void initState() { super.initState(); _controller = AnimationController( duration: widget.duration, vsync: this, ); _animation = Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: _controller, curve: Curves.easeInOut, )); _controller.repeat(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return AnimatedBuilder( animation: _animation, builder: (context, child) { return Transform.scale( scale: 0.5 + (_animation.value * 0.5), child: Opacity( opacity: 1.0 - _animation.value, child: Container( width: widget.size, height: widget.size, decoration: BoxDecoration( shape: BoxShape.circle, color: widget.color ?? Theme.of(context).primaryColor, ), ), ), ); }, ); } } /// 波浪加载动画 class KRSimpleWave extends StatefulWidget { final Color? color; final double size; final Duration duration; const KRSimpleWave({ super.key, this.color, this.size = 40.0, this.duration = const Duration(milliseconds: 1200), }); @override State createState() => _KRSimpleWaveState(); } class _KRSimpleWaveState extends State with TickerProviderStateMixin { late List _controllers; late List> _animations; @override void initState() { super.initState(); _controllers = List.generate(3, (index) { return AnimationController( duration: widget.duration, vsync: this, ); }); _animations = _controllers.map((controller) { return Tween( begin: 0.0, end: 1.0, ).animate(CurvedAnimation( parent: controller, curve: Curves.easeInOut, )); }).toList(); for (int i = 0; i < _controllers.length; i++) { Future.delayed(Duration(milliseconds: i * 200), () { if (mounted) { _controllers[i].repeat(); } }); } } @override void dispose() { for (var controller in _controllers) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: List.generate(3, (index) { return AnimatedBuilder( animation: _animations[index], builder: (context, child) { return Container( margin: const EdgeInsets.symmetric(horizontal: 2.0), width: widget.size / 6, height: widget.size * (0.3 + (_animations[index].value * 0.7)), decoration: BoxDecoration( color: widget.color ?? Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(2.0), ), ); }, ); }), ); } }