You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 23:48:21