Flutter循環(huán)滑動的PageView

序言

Android原生里一般會使用ViewPager來實現(xiàn)Banner區(qū)域腮鞍,當(dāng)然Flutter中的PageView也可以實現(xiàn)類似的效果,今天就來擼一把循環(huán)滑動的PageView。

在Android中想要實現(xiàn)循環(huán)滑動的ViewPager,最常用的方法是,在原數(shù)據(jù)源的基礎(chǔ)上鳄哭,通過前后補(bǔ)位來操作:即準(zhǔn)備新的數(shù)據(jù)集合list , 第一個位置插入原數(shù)據(jù)中的最后一個元素、最后一個位置插入原數(shù)據(jù)中的第一個元素翔怎,F(xiàn)lutter中PageView實現(xiàn)循環(huán)滑動的方法如出一轍,如下圖所示:

在這里插入圖片描述

在用戶滑動過程中杨耙,當(dāng)(2)被選中后赤套,無動畫切換到2的位置;當(dāng)(0)被選中后珊膜,此時無動畫切換到0的位置容握。即可實現(xiàn)循環(huán)滑動的PageView。

準(zhǔn)備新的數(shù)據(jù)源

這里需要解釋下车柠,如果只有一個數(shù)據(jù)的話剔氏,不考慮循環(huán)滑動

  /// 初始化Page
  /// 準(zhǔn)備一個新的數(shù)據(jù)源list
  /// 在原數(shù)據(jù)data的基礎(chǔ)上,前后各添加一個view  data[data.length-1]竹祷、data[0]
  void _initWidget() {
    currentIndex = widget.controller.initialPage;
    if (widget.children == null || widget.children.isEmpty) return;
    if (widget.children.length == 1) {
      _children.addAll(widget.children);
    } else {
      _children.add(widget.children[widget.children.length - 1]);
      _children.addAll(widget.children);
      _children.add(widget.children[0]);
    }
  }

當(dāng)用戶在滑動到新位置的Page后谈跛,會觸發(fā)PageView的回調(diào)監(jiān)聽onPageChanged(int index),參數(shù)即為新選中的Page索引,此時我們需要及時將頁面切換到正確的位置

/// Page切換后的回調(diào)塑陵,及時修復(fù)索引
  _onPageChanged(int index) async {
    if (index == 0) {
      // 當(dāng)前選中的是第一個位置感憾,自動選中倒數(shù)第二個位置
      currentIndex = _children.length - 2;
      await Future.delayed(Duration(milliseconds: 400));
      widget.controller?.get()?.jumpToPage(currentIndex);
      realPosition = currentIndex - 1;
    } else if (index == _children.length - 1) {
      // 當(dāng)前選中的是倒數(shù)第一個位置,自動選中第二個索引
      currentIndex = 1;
      await Future.delayed(Duration(milliseconds: 400));
      widget.controller?.get()?.jumpToPage(currentIndex);
      realPosition = 0;
    } else {
      currentIndex = index;
      realPosition = index - 1;
      if (realPosition < 0) realPosition = 0;
    }
      setState(() {});
  }

你可能會發(fā)現(xiàn)在調(diào)用jumpToPage之前為什么延遲了400毫秒令花,這里做一個短暫的延遲是因為PageView在切換頁面后如果立即jumpToPage會出現(xiàn)卡頓的現(xiàn)象阻桅,做短暫延遲可以規(guī)避這個問題。

定時切換

目前已經(jīng)實現(xiàn)了PageView的循環(huán)滑動兼都,那么現(xiàn)在我們加一個定時器嫂沉,每隔2s自動切換下一個頁面。

/// 創(chuàng)建定時器
  void createTimer() {
    if (widget.isTimer) {
      cancelTimer();
      _timer = Timer.periodic(widget.delay, (timer) => _scrollPage());
    }
  }

/// 定時切換PageView的頁面
  void _scrollPage() {
    ++currentIndex;
    var next = currentIndex % _children?.length;
    widget.controller?.get()?.animateToPage(
          next,
          duration: widget.duration,
          curve: Curves.ease,
        );
  }

/// 開始定時滑動
  void _start() {
    if (!widget.isTimer) return;
    if (!isActive) return;
    if (_children.length <= 1) return;
    createTimer();
  }

/// 停止定時滑動
  void _stop() {
    if (!widget.isTimer) return;
    cancelTimer();
  }

/// 取消定時器
  void cancelTimer() {
    _timer?.cancel();
  }

滑動沖突

到這里就實現(xiàn)了可以定時自動循環(huán)滑動的PageView扮碧,但是看下實際效果你會發(fā)現(xiàn)趟章,當(dāng)用戶在滑動過程中,定時器還在進(jìn)行,此時就需要取消定時器尤揣,當(dāng)用戶手指離開后再開啟定時器自動輪播搔啊。

所以這里你可以給PageView包裹一層NotificationListener來監(jiān)聽用戶滑動

@override
  Widget build(BuildContext context) => NotificationListener(
        onNotification: (notification) => _onNotification(notification),
        child: PageView(
          scrollDirection: widget.scrollDirection,
          reverse: widget.reverse,
          controller: widget.controller?.get(),
          physics: widget.physics,
          pageSnapping: widget.pageSnapping,
          onPageChanged: (index) => _onPageChanged(index),
          children: _children,
          dragStartBehavior: widget.dragStartBehavior,
          allowImplicitScrolling: widget.allowImplicitScrolling,
          restorationId: widget.restorationId,
          clipBehavior: widget.clipBehavior,
        ),
      );
/// Page滑動監(jiān)聽
  _onNotification(notification) {
    if (notification is ScrollStartNotification) {
      isEnd = false;
    } else if (notification is UserScrollNotification) {
      // 用戶滑動時回調(diào)順序:start - user , end - user
      if (isEnd) {
        isUserGesture = false;
        _start();
        return;
      }
      isUserGesture = true;
      _stop();
    } else if (notification is ScrollEndNotification) {
      isEnd = true;
      if (isUserGesture) {
        _start();
      }
    }
  }

值得注意的是,自動滑動和用戶滑動都會觸發(fā)start北戏、end事件负芋,但是用戶滑動時會觸發(fā)user事件,滑動時回調(diào)順序:start - user 嗜愈、 end - user旧蛾,所以只需要在user事件回調(diào)中判斷是否手指離開了,即可區(qū)分用戶滑動和頁面滑動蠕嫁,實現(xiàn)用戶滑動狀態(tài)下暫停定時器锨天,用戶手指離開后啟動定時器。

看下最終的實現(xiàn)效果剃毒,代碼里時加了頁面圓點指示器的病袄,可以參考代碼自定義配置。

插件地址:

Github
pub.dev

UI
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赘阀,一起剝皮案震驚了整個濱河市益缠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌基公,老刑警劉巖幅慌,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異轰豆,居然都是意外死亡胰伍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門酸休,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骂租,“玉大人,你說我怎么就攤上這事斑司∑凶桑” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵陡厘,是天一觀的道長抽米。 經(jīng)常有香客問我,道長糙置,這世上最難降的妖魔是什么云茸? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮谤饭,結(jié)果婚禮上标捺,老公的妹妹穿的比我還像新娘懊纳。我一直安慰自己,他們只是感情好亡容,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布嗤疯。 她就那樣靜靜地躺著,像睡著了一般闺兢。 火紅的嫁衣襯著肌膚如雪茂缚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天屋谭,我揣著相機(jī)與錄音脚囊,去河邊找鬼。 笑死桐磁,一個胖子當(dāng)著我的面吹牛悔耘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播我擂,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼衬以,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了校摩?” 一聲冷哼從身側(cè)響起看峻,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秧耗,沒想到半個月后备籽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舶治,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡分井,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了霉猛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片尺锚。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖惜浅,靈堂內(nèi)的尸體忽然破棺而出瘫辩,到底是詐尸還是另有隱情,我是刑警寧澤坛悉,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布伐厌,位于F島的核電站,受9級特大地震影響裸影,放射性物質(zhì)發(fā)生泄漏挣轨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一轩猩、第九天 我趴在偏房一處隱蔽的房頂上張望卷扮。 院中可真熱鬧荡澎,春花似錦、人聲如沸晤锹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鞭铆。三九已至或衡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衔彻,已是汗流浹背薇宠。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留艰额,地道東北人澄港。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像柄沮,于是被迫代替她去往敵國和親回梧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容