轉載請註明出處:王亟亟的大牛之路
最近在做公司項目的一些模塊遷移的嘗試,然後在改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<StatefulWidget> 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);
}
}
修改指示器背景Widget實現
在繼承和複製之間我選擇了整個文件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<PageIndicator> {
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
基本滿足了設計稿的要求,當然實現的有點粗糙還需要潤色下,這篇還是一次實現過程的經歷,沒有特別的內容分析,謝謝!
有疑問歡迎加我溝通(必須註明來源來意,謝謝)