如何在Flutter中实现带进度条的轮播组件?
Flutter 实现带进度条的轮播组件
既然pub.dev上没找到合适的包,不如自己封装一个——用Flutter原生组件就能实现你要的效果,核心是用PageView做轮播基础,配合AnimationController驱动进度条动画,下面是完整实现方案:
核心实现逻辑
- 用
PageView处理页面切换的核心交互 - 通过
AnimationController控制进度条的填充动画,时长对应页面停留时间 - 监听
PageView的页面切换事件,重置进度动画 - 自动轮播通过动画完成回调触发下一页切换
完整代码示例
import 'package:flutter/material.dart'; class CarouselWithProgressBar extends StatefulWidget { const CarouselWithProgressBar({super.key}); @override State<CarouselWithProgressBar> createState() => _CarouselWithProgressBarState(); } class _CarouselWithProgressBarState extends State<CarouselWithProgressBar> with SingleTickerProviderStateMixin { final PageController _pageController = PageController(initialPage: 0); late AnimationController _progressController; int _currentPage = 0; final int _totalPages = 3; // 可自定义轮播页面数量 bool _isAutoPlaying = true; @override void initState() { super.initState(); // 初始化进度动画控制器,时长3秒(每页停留时间) _progressController = AnimationController( vsync: this, duration: const Duration(seconds: 3), ); _startAutoPlay(); } @override void dispose() { _pageController.dispose(); _progressController.dispose(); super.dispose(); } // 启动自动轮播逻辑 void _startAutoPlay() { if (!_isAutoPlaying) return; _progressController.forward().then((_) { // 切换到下一页,最后一页跳回第一页 if (_currentPage < _totalPages - 1) { _pageController.nextPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } else { _pageController.jumpToPage(0); } _progressController.reset(); _startAutoPlay(); }); } // 页面切换时重置进度条 void _onPageChanged(int page) { setState(() { _currentPage = page; }); _progressController.reset(); if (_isAutoPlaying) { _progressController.forward(); } } @override Widget build(BuildContext context) { return Column( children: [ // 轮播主体区域 SizedBox( height: 220, // 自定义轮播高度 child: PageView( controller: _pageController, onPageChanged: _onPageChanged, children: List.generate(_totalPages, (index) { // 这里可以替换成自定义的轮播内容 return Container( color: index % 2 == 0 ? Colors.lightBlue[100] : Colors.pink[100], alignment: Alignment.center, child: Text( '轮播页面 ${index + 1}', style: const TextStyle(fontSize: 26, fontWeight: FontWeight.w600), ), ); }), ), ), const SizedBox(height: 16), // 进度条+控制按钮区域 Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ // 线性进度条 Expanded( child: AnimatedBuilder( animation: _progressController, builder: (context, child) { return LinearProgressIndicator( value: _progressController.value, backgroundColor: Colors.grey[200], valueColor: const AlwaysStoppedAnimation<Color>(Colors.blueAccent), borderRadius: BorderRadius.circular(4), ); }, ), ), const SizedBox(width: 12), // 上一页按钮 IconButton( icon: const Icon(Icons.chevron_left, size: 28), onPressed: () { _pageController.previousPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); }, ), // 播放/暂停按钮 IconButton( icon: Icon(_isAutoPlaying ? Icons.pause_circle : Icons.play_circle, size: 28), onPressed: () { setState(() { _isAutoPlaying = !_isAutoPlaying; if (_isAutoPlaying) { _progressController.forward(); _startAutoPlay(); } else { _progressController.stop(); } }); }, ), // 下一页按钮 IconButton( icon: const Icon(Icons.chevron_right, size: 28), onPressed: () { _pageController.nextPage( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); }, ), ], ), ), ], ); } } // 使用示例 void main() { runApp(const MaterialApp( home: Scaffold( appBar: AppBar(title: Text('带进度条的轮播')), body: Center(child: CarouselWithProgressBar()), ), )); }
自定义扩展建议
- 进度条样式:可以把线性进度条改成圆形进度条,或者自定义进度条的颜色、高度
- 内容自定义:把轮播页面改成传入的
List<Widget>,封装成通用组件 - 手势交互优化:监听滑动手势,滑动时暂停自动播放,滑动结束后恢复
- 页面指示器:可以在进度条旁添加小点指示器,和进度条配合使用
内容的提问来源于stack exchange,提问作者bi joop
相关产品推荐
相关产品推荐

