轮播图
- CarouselView系统自带的,基于CustomScrollView。
- CarouselSlider 第三方插件,基于PageView。
CarouselView
- reverse 默认第一页往左,右边出来第二页。这里设置true。则手势方向往右,第二页从左边出来。
shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),默认会有圆角,这里取消圆角。padding: EdgeInsets.zero,默认会有边距,这里取消边距。itemSnapping保证按页显示,第一页完整显示。如果有多个页面,只保证第一个完整显示。
arduino
// CarouselView 是 Material 3 的轮播组件(Flutter 3.27+)。
// 必填参数:
// - itemExtent: 每个 item 在主轴方向的固定尺寸
// - children: 要展示的子项
// 常用可选参数:
// - padding: 每个 item 外侧的内边距,默认 EdgeInsets.all(4)
// - backgroundColor: 每个 item 的背景色(默认取 surface)
// - elevation: 每个 item 的阴影高度,默认 0
// - shape: 每个 item 的形状,默认圆角 28 的 RoundedRectangleBorder
// - itemSnapping: 是否启用"吸附到 item"效果,默认 false
// - shrinkExtent: 滚动时首/尾 item 的最小尺寸,默认 0
// - onTap: 点击某个 item 时回调,参数为索引
// - onIndexChanged: "首位可见 item"变化时回调
// - enableSplash: 是否有 InkWell 水波纹,默认 true
less
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('CarouselView Test')),
body: CarouselViewTest(),
),
),
);
}
class CarouselViewTest extends StatefulWidget {
CarouselViewTest({Key? key}) : super(key: key);
@override
_CarouselViewTestState createState() => _CarouselViewTestState();
}
class _CarouselViewTestState extends State<CarouselViewTest> {
CarouselController carouselController = CarouselController();
int _currentIndex = 0;
@override
void initState() {
super.initState();
// 方式二:通过 controller 监听(可以拿到实时 offset、判断动画过程等)
carouselController.addListener(() {
// 滚动过程中随时可以读取当前偏移和 leadingItem
// print('实时 pixels: ${carouselController.position.pixels}');
// print('实时 leadingItem: ${carouselController.leadingItem}');
});
}
@override
void dispose() {
carouselController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
color: Colors.green,
child: CarouselView(
// reverse: true,
controller: carouselController,
itemExtent: MediaQuery.of(context).size.width,
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),
itemSnapping: true,
// 方式一:onIndexChanged 回调,翻页完成后触发(推荐)
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
});
debugPrint('切到了第 $index 页');
},
children: [
Container(color: Colors.red),
Container(color: Colors.blue),
Container(color: Colors.yellow),
],
),
),
// 底部指示器
Positioned(
bottom: 20,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (i) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
width: _currentIndex == i ? 20 : 8,
height: 8,
decoration: BoxDecoration(
color: _currentIndex == i ? Colors.white : Colors.white54,
borderRadius: BorderRadius.circular(4),
),
);
}),
),
),
],
);
}
}
对于页面控制
arduino
// controller 接收的是 CarouselController(不是 ScrollController)。
// 常用 API:
// - animateToItem(index, {duration, curve}): 动画滚到指定项
// - jumpToItem(index): 瞬间跳到指定项
// - leadingItem: 当前"首位可见 item"的索引
// - initialItem: 初始化时让第 N 项作为首位可见
// 同时配合 onIndexChanged 回调可以监听首位变化。
动态控制每一个Item的占比
scala
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('CarouselView Test')),
body: CarouselViewTest(),
),
),
);
}
class CarouselViewTest extends StatefulWidget {
CarouselViewTest({Key? key}) : super(key: key);
@override
_CarouselViewTestState createState() => _CarouselViewTestState();
}
class _CarouselViewTestState extends State<CarouselViewTest> {
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: CarouselView.weighted(
// flexWeights: [1, 2, 1], // 显示3个
flexWeights: [1, 2, 1, 2], // 显示4个
onIndexChanged: (int index) {},
children: [
Container(color: Colors.red),
Container(color: Colors.blue),
Container(color: Colors.yellow),
Container(color: Colors.black),
],
),
);
}
}
动态添加
数量太多,一次增加会内存消耗过多。
less
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('CarouselView Test')),
body: CarouselViewTest(),
),
),
);
}
class CarouselViewTest extends StatefulWidget {
CarouselViewTest({Key? key}) : super(key: key);
@override
_CarouselViewTestState createState() => _CarouselViewTestState();
}
class _CarouselViewTestState extends State<CarouselViewTest> {
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: CarouselView.builder(
itemExtent: 200,
itemCount: 1000,
itemBuilder: (BuildContext context, int index) {
// 黄金角分布,每个 index 颜色不同且稳定(不随 rebuild 闪烁)
final hue = (index * 137.508) % 360;
return Container(
color: HSLColor.fromAHSL(1.0, hue, 0.7, 0.5).toColor(),
alignment: Alignment.center,
child: Text(
'$index',
textAlign: TextAlign.center,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 40, color: Colors.white),
),
);
},
),
);
}
}
无限轮播图
less
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('CarouselView Test')),
body: CarouselViewTest(),
),
),
);
}
class CarouselViewTest extends StatefulWidget {
CarouselViewTest({Key? key}) : super(key: key);
@override
_CarouselViewTestState createState() => _CarouselViewTestState();
}
class _CarouselViewTestState extends State<CarouselViewTest> {
CarouselController carouselController = CarouselController();
int _currentIndex = 0;
@override
void initState() {
super.initState();
// 方式二:通过 controller 监听(可以拿到实时 offset、判断动画过程等)
carouselController.addListener(() {
// 滚动过程中随时可以读取当前偏移和 leadingItem
// print('实时 pixels: ${carouselController.position.pixels}');
// print('实时 leadingItem: ${carouselController.leadingItem}');
});
}
@override
void dispose() {
carouselController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
color: Colors.green,
child: CarouselView(
controller: carouselController,
infinite: true,
itemExtent: MediaQuery.of(context).size.width,
padding: EdgeInsets.zero,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.zero),
itemSnapping: true,
// 方式一:onIndexChanged 回调,翻页完成后触发(推荐)
onIndexChanged: (int index) {
setState(() {
_currentIndex = index;
});
debugPrint('切到了第 $index 页');
},
children: [
Container(color: Colors.red),
Container(color: Colors.blue),
Container(color: Colors.yellow),
],
),
),
// 底部指示器
Positioned(
bottom: 20,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (i) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 4),
width: _currentIndex == i ? 20 : 8,
height: 8,
decoration: BoxDecoration(
color: _currentIndex == i ? Colors.white : Colors.white54,
borderRadius: BorderRadius.circular(4),
),
);
}),
),
),
],
);
}
}
CarouselSlider
-
CarouselSlider()------ 静态列表
-
CarouselSlider.builder()------ 按需构建(推荐,节省内存)
less
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('CarouselView Test')),
body: CarouselViewTest(),
),
),
);
}
class CarouselViewTest extends StatefulWidget {
CarouselViewTest({Key? key}) : super(key: key);
@override
_CarouselViewTestState createState() => _CarouselViewTestState();
}
class _CarouselViewTestState extends State<CarouselViewTest> {
@override
Widget build(BuildContext context) {
return CarouselSlider(
items: [
// 这里设置宽度无效,是CarouselOptions的viewportFraction控制的
Container(color: Colors.red, width: MediaQuery.of(context).size.width),
Container(color: Colors.blue, width: MediaQuery.of(context).size.width),
Container(
color: Colors.yellow,
width: MediaQuery.of(context).size.width,
),
],
options: CarouselOptions(
height:300,
autoPlay: true,
aspectRatio: 16 / 9,
viewportFraction: 1,
),
);
}
}