flutter flutter_swiper自定義指示器

轉載請註明出處:王亟亟的大牛之路

最近在做公司項目的一些模塊遷移的嘗試,然後在改Banner的時候發現官方並沒有提供封裝徹底的ViewPager控件,然後第三方里我選了 https://github.com/best-flutter/flutter_swiper
理由有以下幾點

  1. 有人維護,且仍在繼續開發
  2. 文檔解釋比較清晰
  3. 使用比較簡便
  4. 滿足了業務效果

官方的演示效果
在這裏插入圖片描述
設計稿長這樣
在這裏插入圖片描述

可以發現他的指示器是圓的,然而我們的是方的,所以帶着疑問我看了下他的文檔

在這裏插入圖片描述
官方對自定義指示器是有支持的,先看一下他支持傳入什麼控件

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

基本滿足了設計稿的要求,當然實現的有點粗糙還需要潤色下,這篇還是一次實現過程的經歷,沒有特別的內容分析,謝謝!

有疑問歡迎加我溝通(必須註明來源來意,謝謝)
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章