先贴一下运行效果
在开发过程中往往会遇到需求是这样的,我们要实现的效果如图二所示。
项目中使用的轮播图插件是:
通过查阅Swipe_pagination的源代码可知,目前只提供了FractionPaginationBuilder(百分数类型的,例如:1/5)、RectSwipePaginationBuilder(矩形)、DotSwiperPaginationBuilder(圆点)。像我们目前的需求就是做带圆角的,选中的是带圆角的圆柱,未选中的是圆点。
最终通过复制修改代码(swipe_pagination.dart)实现的功能
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart';
class SquareSwiperPaginationBuilder extends SwiperPlugin {
///color when current index,if set null , will be Theme.of(context).primaryColor
final Color activeColor;
///,if set null , will be Theme.of(context).scaffoldBackgroundColor
final Color color;
///Size of the dot when activate
final double activeSize;
///Size of the dot
final double size;
/// Space between dots
final double space;
///加了一个自定义高度的参数,如果要使用Size.height 的话需要修改size的类型(double->Size),这样的话也需要重新写PageIndicator,过犹不及了。
///Height of the dots
final double height;
final Key key;
const SquareSwiperPaginationBuilder(
{this.activeColor,
this.color,
this.key,
this.height: 4.0,
this.size: 4.0,
this.activeSize: 10.0,
this.space: 3.0});
@override
Widget build(BuildContext context, SwiperPluginConfig config) {
if (config.itemCount > 20) {
print(
"The itemCount is too big, we suggest use FractionPaginationBuilder instead of DotSwiperPaginationBuilder in this sitituation");
}
Color activeColor = this.activeColor;
Color color = this.color;
if (activeColor == null || color == null) {
ThemeData themeData = Theme.of(context);
activeColor = this.activeColor ?? themeData.primaryColor;
color = this.color ?? themeData.scaffoldBackgroundColor;
}
if (config.indicatorLayout != PageIndicatorLayout.NONE &&
config.layout == SwiperLayout.DEFAULT) {
return new PageIndicator(
count: config.itemCount,
controller: config.pageController,
layout: config.indicatorLayout,
size: size,
activeColor: activeColor,
color: color,
space: space,
);
}
List list = [];
int itemCount = config.itemCount;
int activeIndex = config.activeIndex;
for (int i = 0; i < itemCount; ++i) {
bool active = i == activeIndex;
list.add(Container(
key: Key("pagination_$i"),
margin: EdgeInsets.all(space),
child: active
? SizedBox(
width: activeSize,
height: height,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(height / 2)),
color: activeColor),
),
)
: SizedBox(
width: size,
height: height,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(height / 2)),
color: color),
),
),
));
}
if (config.scrollDirection == Axis.vertical) {
return new Column(
key: key,
mainAxisSize: MainAxisSize.min,
children: list,
);
} else {
return new Row(
key: key,
mainAxisSize: MainAxisSize.min,
children: list,
);
}
}
}
typedef Widget SwiperPaginationBuilder(
BuildContext context, SwiperPluginConfig config);
class SwiperCustomPagination extends SwiperPlugin {
final SwiperPaginationBuilder builder;
SwiperCustomPagination({@required this.builder});
@override
Widget build(BuildContext context, SwiperPluginConfig config) {
return builder(context, config);
}
}
class SquareSwiperPagination extends SwiperPlugin {
static const SwiperPlugin square = const SquareSwiperPaginationBuilder();
/// Alignment.bottomCenter by default when scrollDirection== Axis.horizontal
/// Alignment.centerRight by default when scrollDirection== Axis.vertical
final Alignment alignment;
/// Distance between pagination and the container
final EdgeInsetsGeometry margin;
/// Build the widet
final SwiperPlugin builder;
final Key key;
const SquareSwiperPagination(
{this.alignment,
this.key,
this.margin: const EdgeInsets.all(10.0),
this.builder: SquareSwiperPagination.square});
Widget build(BuildContext context, SwiperPluginConfig config) {
Alignment alignment = Alignment.bottomCenter;
Widget child = Container(
margin: margin,
child: this.builder.build(context, config),
);
///拿掉这个判断之后,使得指示器无论在轮播图之上还是下面都可以居中
// if (!config.outer) {
child = new Align(
key: key,
alignment: alignment,
child: child,
);
// }
return child;
}
}
大部分代码都是源代码,主要是改了最后list.add(Container(...))部分(大约在第70行代码附近),通过active的判断,返回不同的Widget。
在实际使用中就可以这样写:
这样就可以实现如文章顶部第二个轮播图的效果。
同时,自定义的指示器的代码里面还加入了一个height参数,用来设置指示器的高度。可以通过设置size和activeSize一致,或包含height,再控制圆角实现, 实现矩形的定长指示器,这里不再赘述。