flutter:carousel_slider与轮播图

  1. 是什么
  2. CarouselSlider 的属性
  3. CarouselOptions 的属性
    1. 常用属性
    2. autoPlayCurve
  4. CarouselSliderController 的方法
  5. 安装依赖
  6. 基本用法
  7. 带指示器 + controller

是什么

carousel_slider 是一个 Flutter 第三方包,用来快速实现 图片/内容轮播(走马灯) 的效果。它的核心是一个 CarouselSlider Widget,比原生的 PageView 更方便:

  • 自动播放(auto play)

  • 无限循环(infinite loop)

  • 自定义滑动动画

  • 支持显示多个 item(类似缩略图效果)

  • 内置了指示器(dots)

可以理解成: PageView 的高级封装,专门用来做轮播图。

它主要有 两个核心类

  1. CarouselSlider → 用来展示轮播内容的组件
  2. CarouselController → 用来手动控制轮播(跳转、播放、停止等)

还有一个重要的配置类:

  1. CarouselOptions → 用来配置轮播的行为和外观

CarouselSlider 的属性

CarouselSlider({
  Key? key,
  required List<Widget> items,     // 或者使用 itemBuilder
  required CarouselOptions options,
  CarouselController? carouselController,
  int? itemCount,                  // 和 itemBuilder 搭配使用
  IndexedWidgetBuilder? itemBuilder,
})
  • items:一个 List<Widget>,每个元素就是一页(图片、卡片、任何 Widget)
  • itemCount + itemBuilder:如果数据很多,可以用懒加载(和 ListView.builder 一样)
  • options:传入 CarouselOptions 配置
  • carouselController:传入 CarouselController,方便外部手动控制

CarouselOptions 的属性

常用属性

属性 类型 说明
height double 轮播图高度
aspectRatio double 宽高比(比如 16/9)
viewportFraction double 每个页面占据屏幕的比例(默认 1.0,设置 <1 可以看到左右的预览)
initialPage int 初始页面索引
enableInfiniteScroll bool 是否无限循环(默认 true)
reverse bool 是否反向滚动
autoPlay bool 是否自动播放
autoPlayInterval Duration 自动播放的间隔时间
autoPlayAnimationDuration Duration 自动播放时的动画时间
autoPlayCurve Curve 动画曲线(如 Curves.easeInOut
enlargeCenterPage bool 是否让中间的页面放大(卡片轮播效果)
enlargeFactor double 放大比例(默认 0.3)
scrollDirection Axis 滑动方向(水平 or 垂直)
pauseAutoPlayOnTouch bool 手指触摸时是否暂停自动播放(某些版本已废弃,改成 pauseAutoPlayInFiniteScroll
onPageChanged Function(int index, CarouselPageChangedReason reason) 页面切换回调

autoPlayCurve

匀速 & 线性

  • Curves.linear → 匀速动画,没有加速减速

先慢后快 / 先快后慢

  • Curves.easeIn → 开始慢,结尾快
  • Curves.easeOut → 开始快,结尾慢
  • Curves.easeInOut → 开始和结尾都慢,中间快(最常用)

加速 & 弹性

  • Curves.fastOutSlowIn → 开始快,结尾慢(Material Design 默认)
  • Curves.decelerate → 快速开始,逐渐减速
  • Curves.bounceIn → 开始有弹跳效果
  • Curves.bounceOut → 结束有弹跳效果
  • Curves.bounceInOut → 开始和结束都有弹跳

弹簧 & 超冲

  • Curves.elasticIn → 开始时回弹一下再进入
  • Curves.elasticOut → 结束时回弹一下
  • Curves.elasticInOut → 开始和结束都有弹簧感

CarouselSliderController 的方法

用来手动控制轮播,比如点击按钮切换页面:

final CarouselSliderController _controller = CarouselSliderController();
方法 说明
nextPage({Duration duration, Curve curve}) 跳到下一页
previousPage({Duration duration, Curve curve}) 跳到上一页
jumpToPage(int page) 无动画直接跳转到某一页
animateToPage(int page, {Duration duration, Curve curve}) 带动画跳转到某一页
startAutoPlay() 开始自动播放
stopAutoPlay() 停止自动播放

安装依赖

在项目中运行:

flutter pub add carousel_slider

或者在 pubspec.yaml 里加:

dependencies:
  carousel_slider: ^5.0.0   # 实际版本请以 pub.dev 为准

基本用法

import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: CarouselDemo());
  }
}

class CarouselDemo extends StatelessWidget {
  final List<String> imgList = [
    'https://picsum.photos/800/400?img=1',
    'https://picsum.photos/800/400?img=2',
    'https://picsum.photos/800/400?img=3',
  ];

  CarouselDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("CarouselSlider Demo")),
      body: CarouselSlider(
        options: CarouselOptions(
          height: 400.0,
          autoPlay: true, // 自动播放
          enlargeCenterPage: true, // 当前页面居中放大
          viewportFraction: 0.8, // 页面显示的比例(0.8表示留一点左右空隙)
          aspectRatio: 16 / 9, // 宽高比
          autoPlayInterval: Duration(seconds: 3), // 自动播放间隔
          autoPlayAnimationDuration: Duration(milliseconds: 800), // 动画时间
          enableInfiniteScroll: true, // 无限循环
        ),
        // final List<Widget>? items;
        items: imgList.map((item) {
          return Builder(
            builder: (BuildContext context) {
              return Container(
                width: MediaQuery.of(context).size.width,
                margin: EdgeInsets.symmetric(horizontal: 5.0),
                decoration: BoxDecoration(color: Colors.amber),
                child: Image.network(item, fit: BoxFit.cover),
              );
            },
          );
        }).toList(),
      ),
    );
  }
}
  • 轮播图自动播放
  • 手指可以滑动切换
  • 无限循环

带指示器 + controller

import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: CarouselWithDots());
  }
}

class CarouselWithDots extends StatefulWidget {
  const CarouselWithDots({super.key});

  @override
  _CarouselWithDotsState createState() => _CarouselWithDotsState();
}

class _CarouselWithDotsState extends State<CarouselWithDots> {
  final List<String> imgs = [
    'https://picsum.photos/800/400?img=1',
    'https://picsum.photos/800/400?img=2',
    'https://picsum.photos/800/400?img=3',
  ];
  final CarouselSliderController _ctrl = CarouselSliderController();
  int _current = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // CarouselSlider: 轮播图组件
        CarouselSlider.builder(
          itemCount: imgs.length,
          carouselController: _ctrl,
          itemBuilder: (context, index, pageIndex) {
            // ClipRRect: 得到一个圆角矩形
            return ClipRRect(
              borderRadius: BorderRadius.circular(12),
              child: Image.network(
                imgs[index],
                fit: BoxFit.cover,
                // double.infinity: 无限宽度,也就是铺满屏幕的宽度
                width: double.infinity,
              ),
            );
          },
          options: CarouselOptions(
            height: 420,
            autoPlay: true,
            // 使当前页面放大
            enlargeCenterPage: true,
            // onPageChanged 是一个回调函数,当页面改变时触发
            // index 是当前页面的索引,reason 是页面改变的原因
            onPageChanged: (index, reason) {
              setState(() => _current = index);
            },
          ),
        ),
        // Row: 指示器,也就是下面的圆点
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          // List.generate: 生成一个列表
          children: List.generate(imgs.length, (i) {
            // GestureDetector: 手势检测器
            return GestureDetector(
              // 点击圆点时,跳转到对应的页面
              onTap: () => _ctrl.animateToPage(
                i,
                duration: Duration(milliseconds: 300),
                curve: Curves.ease,
              ),
              child: Container(
                // width: 12, height: 12: 当前选中的圆点
                // width: 8, height: 8: 其他圆点
                width: _current == i ? 12 : 8,
                height: _current == i ? 12 : 8,
                // 圆点之间的间距
                margin: EdgeInsets.symmetric(horizontal: 6, vertical: 10),
                // decoration: 装饰器
                decoration: BoxDecoration(
                  // 如果是当前选中的圆点,颜色为蓝色,否则为灰色
                  color: _current == i ? Colors.blue : Colors.grey,
                  // shape: 形状,BoxShape.circle: 圆形
                  shape: BoxShape.circle,
                ),
              ),
            );
          }),
        ),
      ],
    );
  }
}

carousel_slider 里,animateToPageitemBuilderitemCount 之间的关系,其实和 PageView 几乎一样,因为它的底层就是基于 PageView 封装的。

  • itemCount:告诉轮播有多少个 item(页数)。
  • itemBuilder:根据 index 去构建具体的 Widget。
  • index 的范围是 0 ..< itemCount-1
  • 当你用 animateToPage(2),轮播内部会调用 itemBuilder(context, 2) 去构建第 3 页的内容。它和 PageView.builder(itemCount, itemBuilder) 的机制 完全一致
  • animateToPage(int page, {duration, curve})的作用是跳转到指定的 页码0 开始计数)。它会检查 itemCount 的范围,然后执行切换动画。切换完成后,会触发 onPageChanged 回调。

×

喜欢就点赞,疼爱就打赏