flutter_swiper内置了2种分页指示器,一种是SwiperPagination.dots的圆形风格,一种是SwiperPagination.fraction的数字风格,但是这显然不能满足我们的需要,比如下图这种效果:
flutter_swiper提供了这样的能力,但是需要你自己实现
你可以看到这文档简直简单,就一个方法就没了,让人摸不到头脑。不慌,你可以看SwiperPagination.dots的实现,就发现其实就一个StatefulWidget,参考源码后,我的代码如下:
新建一个custom_swiper_pagination.dart(flutter2.x+card_swiper 此库是flutter_swiper的空安全版)
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:card_swiper/card_swiper.dart';
/// 自定义页面指示器
class CustomSwiperPaginationBuilder extends SwiperPlugin {
// 当滚动到此时的颜色
late Color? activeColor;
// 默认颜色
late Color? color;
// 每个圆点的间距
final double space;
// 每个圆点的大小
final double size;
// 特殊点的宽度
final double activeSize;
final double bottom;
final AlignmentGeometry? alignment;
final Key? key;
CustomSwiperPaginationBuilder(
{this.color = Colors.grey,
this.activeColor = Colors.blue,
this.space = 3.0,
this.size = 6.0,
this.activeSize = 20.0,
this.bottom = 0.0,
this.alignment = Alignment.center,
this.key});
@override
Widget build(BuildContext context, SwiperPluginConfig config) {
// 处理边界情况
if (config.itemCount > 20) {
log(
'The itemCount is too big, we suggest use FractionPaginationBuilder '
'instead of DotSwiperPaginationBuilder in this situation',
);
}
int activeIndex = config.activeIndex;
// 用于存放小圆点
List list = [];
for (var i = 0; i < config.itemCount; ++i) {
if (activeIndex == i) {
list.add(Container(
key: Key('pagination_$i'),
margin: EdgeInsets.all(space),
child: PhysicalModel(
color: Colors.transparent,
borderRadius: BorderRadius.circular(10),
clipBehavior: Clip.antiAlias,
child: Container(
color: activeColor,
width: activeSize,
height: size,
),
)));
} else {
list.add(Container(
key: Key('pagination_$i'),
margin: EdgeInsets.all(space),
child: ClipOval(
// 圆角组件
child: Container(
color: color,
width: size,
height: size,
),
),
));
}
}
return Stack(
clipBehavior: Clip.none,
children: [
Positioned(
left: 15,
right: 15,
bottom: bottom,
child: Container(
alignment: alignment,
color: Colors.transparent,
child: Row(
key: key,
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: list,
),
))
],
);
}
}
使用此方法:
child: Swiper(
itemBuilder: (BuildContext context, int index) {
var swiperItem = swiperList[index];
return PhysicalModel(
color: Colors.transparent,
borderRadius: BorderRadius.circular(10),
clipBehavior: Clip.antiAlias,
child: Image.network(
swiperItem?.img ?? '',
fit: BoxFit.cover,
),
);
},
viewportFraction: 0.85,
scale: 0.9,
autoplay: swiperList.isNotEmpty,
itemCount: swiperList.length,
pagination: SwiperPagination( // 此处使用自己编写的样式
builder: CustomSwiperPaginationBuilder(alignment: Alignment.bottomCenter),
),
// control: const SwiperControl(),
),
flutter_swiper默认是在图片内部的,因为我需要它显示在外面,因此使用了Stack组件。
注意:autoplay: swiperList.isNotEmpty最好使用isNotEmpty而不是true,否则就可能出现下面这种情况:
最终效果: