// Author: fruit.com.cn import 'package:flutter/material.dart'; /// 播放未就绪时沿进度轨道循环移动的加载高光。 class LoadingProgressTrack extends StatefulWidget { const LoadingProgressTrack({ super.key = const Key('progress-loading'), required this.height, this.trackColor = Colors.white24, this.highlightColor = Colors.white, }); final double height; final Color trackColor; final Color highlightColor; @override State createState() => _LoadingProgressTrackState(); } class _LoadingProgressTrackState extends State with SingleTickerProviderStateMixin, WidgetsBindingObserver { late final AnimationController _controller; late final Animation _position; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 1200), ); _position = CurvedAnimation(parent: _controller, curve: Curves.easeInOut); WidgetsBinding.instance.addObserver(this); _syncAnimation(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); _syncAnimation(); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); _controller.dispose(); super.dispose(); } void _syncAnimation() { if (WidgetsBinding.instance.lifecycleState == AppLifecycleState.resumed) { if (!_controller.isAnimating) _controller.repeat(); } else { _controller.stop(); } } @override Widget build(BuildContext context) { return SizedBox( height: widget.height, child: ClipRRect( borderRadius: BorderRadius.circular(widget.height / 2), child: LayoutBuilder( builder: (context, constraints) { final highlightWidth = constraints.maxWidth * 0.28; final travel = constraints.maxWidth + highlightWidth; return AnimatedBuilder( animation: _position, builder: (context, _) { final left = -highlightWidth + travel * _position.value; return Stack( fit: StackFit.expand, children: [ ColoredBox( key: const Key('progress-loading-track'), color: widget.trackColor, ), Positioned( left: left, top: 0, bottom: 0, width: highlightWidth, child: ColoredBox( key: const Key('progress-loading-highlight'), color: widget.highlightColor, ), ), ], ); }, ); }, ), ), ); } }