是什么
carousel_slider 是一个 Flutter 第三方包,用来快速实现 图片/内容轮播(走马灯) 的效果。它的核心是一个 CarouselSlider Widget,比原生的 PageView 更方便:
自动播放(auto play)
无限循环(infinite loop)
自定义滑动动画
支持显示多个 item(类似缩略图效果)
内置了指示器(dots)
可以理解成: PageView 的高级封装,专门用来做轮播图。
它主要有 两个核心类:
CarouselSlider→ 用来展示轮播内容的组件CarouselController→ 用来手动控制轮播(跳转、播放、停止等)
还有一个重要的配置类:
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 里,animateToPage、itemBuilder、itemCount 之间的关系,其实和 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回调。