最近在做公司项目的一些模块迁移的尝试,然后在改Banner的时候发现官方并没有提供封装彻底的ViewPager
控件,然后第三方里我选了 https://github.com/best-flutter/flutter_swiper
理由有以下几点
可以发现他的指示器是圆的,然而我们的是方的,所以带着疑问我看了下他的文档
class SwiperCustomPagination extends SwiperPlugin {
final SwiperPaginationBuilder builder;
SwiperCustomPagination({@required this.builder}) : assert(builder != null);
@override
Widget build(BuildContext context, SwiperPluginConfig config) {
return builder(context, config);
}
}
可以传任意控件,那我们假装丢个text试试看
试试发现是有效的,带着疑问去看一下他的指示器实现类PageIndicator
开源团队把指示器这块单独做了一个依赖lib在https://github.com/best-flutter/flutter_page_indicator
PageIndicator(
{Key key,
this.size: 20.0,
this.space: 5.0,
this.count,
this.activeSize: 20.0,
this.controller,
this.color: Colors.white30,
this.layout: PageIndicatorLayout.SLIDE,
this.activeColor: Colors.white,
this.scale: 0.6,
this.dropHeight: 20.0})
: assert(count != null),
assert(controller != null),
super(key: key);
@override
State createState() {
return new _PageIndicatorState();
}
}
构造函数一大堆但是我们真正在乎的其实只有this.layout: PageIndicatorLayout.SLIDE,
这是具体那个View的实现,当然官方提供了很多种类型,大家可以自己去看我这边选择了PageIndicatorLayout.NONE
进行改造
对外暴露的枚举类型决定了调用哪个子类的实现,为了不破坏原有的类型,这边就添加一个新的枚举值
enum PageIndicatorLayout {
NONE,
SLIDE,
WARM,
COLOR,
SCALE,
DROP,
NIO,//你自己随便定吧
}
这便是拿NonePainter实现进行修改,区别就是把画圆的动画过程全部变成了画线
class NioPainter extends NioBasePainter {
NioPainter(PageIndicator widget, double page, int index, Paint paint)
: super(widget, page, index, paint);
@override
void draw(Canvas canvas, double space, double size, double radius) {
double secondOffset = index == widget.count - 1
? radius
: radius + ((index + 1) * (size + space));
_paint.color = styles.ComponentStyle.APP_MAIN_COLOR;
_paint.strokeWidth = 3;
//只修改这里就可以满足效果
canvas.drawLine(new Offset(secondOffset - 8, radius),
new Offset(secondOffset + 8, radius), _paint);
}
}
在继承和复制之间我选择了整个文件copy然后在内部改造,继承还要看原来的代码里是否暴露了足够的成员方法,个人觉得不是太有必要,索性直接copy,反正也就一个文件。
背景点的实现就在BasePainter里,他是一个抽象类,里面代码里几十行,但是我们其实只需要把默认的背景灰点换成直线就行,找到paint
方法进行修改。
abstract class NioBasePainter extends BasePainter {
...
@override
void paint(Canvas canvas, Size size) {
_paint.color = widget.color;
double space = widget.space;
double size = widget.size;
double radius = size / 2;
for (int i = 0, c = widget.count; i < c; ++i) {
if (_shouldSkip(i)) {
continue;
}
//8只是一种横线多宽自己算吧,反正就是一个不同x坐标同y坐标的一条直线
canvas.drawLine(new Offset(i * (size + space) + radius - 8, radius),
new Offset(i * (size + space) + radius + 8, radius), _paint);
}
double page = this.page;
if (page < index) {
page = 0.0;
}
_paint.color = widget.activeColor;
draw(canvas, space, size, radius);
}
}
...省略其他代码
class _PageIndicatorState extends State {
BasePainter _createPainer() {
switch (widget.layout) {
case PageIndicatorLayout.NIO:
//添加自己新加的枚举值多对应的动态指示器实现
return new NioPainter(
widget, widget.controller.page ?? 0.0, index, _paint);
...省略其他代码
default:
throw new Exception("Not a valid layout");
}
}
}
源码地址:https://github.com/ddwhan0123/flutter_tutorial/blob/master/lib/component/widget/page_indicator.dart
基本满足了设计稿的要求,当然实现的有点粗糙还需要润色下,这篇还是一次实现过程的经历,没有特别的内容分析,谢谢!