Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ViewPager的onPageScrolled回調不完整

ViewPager的onPageScrolled回調不完整

編輯:關於Android編程

問題描述

在開發時我們可能經常需要使用到ViewPager的onPageScrolled(int position, float offset, int offsetPixels)方法來獲取ViewPager的滾動信息,然而在使用中發現onPageScrolled並不能准確地回調每一個滾動信息,可能會錯過一些信息,在一些手機上甚至連onPageScrolled滾動停止(offset參數為0的狀態)的信息也不會回調。

問題分析

通過閱讀ViewPager的源碼知道,ViewPager的滾動是配合Scroller實現的,而Scroller的實現原理就是在Scroller的動畫時間內不斷的調整View的位置然後重繪布局,而onPageScrolled的回調和view位置的調整是同步的,但是View的重新繪制是耗時的,這也就是說,onPageScrolled的回調頻率和view的重新繪制相關聯,如果手機的性能差一點,View的刷新次數少,那麼onPageScrolled的回調次數也會相對減少。

後來又發現onPageScrolled的最終狀態的回調在部分手機上存在問題,有部手機很卡也能正常回調,有部手機比較流暢卻也沒有回調,所以可能和安卓系統版本有關,於是對比了一下ViewPager在各個版本的實現,發現了問題;我們知道要通過Scroller實現滾動需要實現computeScroll方法,在這個方法裡判斷滾動是否已完成,沒有完成則通過scrollTo方法滾動到相應的位置。下面是ViewPager的實現:

@Override
public void computeScroll() {
    if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
        int oldX = getScrollX();
        int oldY = getScrollY();
        int x = mScroller.getCurrX();
        int y = mScroller.getCurrY();
        if (oldX != x || oldY != y) {
            scrollTo(x, y);
            if (!pageScrolled(x)) {
                mScroller.abortAnimation();
                scrollTo(0, y);
            }
        }

        // Keep on drawing until the animation has finished.
        ViewCompat.postInvalidateOnAnimation(this);
        return;
    }

    // Done with scroll, clean up state.
    completeScroll(true);
}

可以看到如果mScroller沒有Finished則會通過pageScrolled回調onPageScrolled 並滾動到指定位置,如果已經Finished則調用completeScroll方法完成最終的狀態,我們的問題是onPageScrolled在最終狀態的調用在有些手機上不正常,所以這其中的玄機很可能發生在completeScroll方法中,於是進一步查看completeScroll方法:

private void completeScroll(boolean postEvents) {
    boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING;
    if (needPopulate) {
        // Done with scroll, no longer want to cache view drawing.
        setScrollingCacheEnabled(false);
        mScroller.abortAnimation();
        int oldX = getScrollX();
        int oldY = getScrollY();
        int x = mScroller.getCurrX();
        int y = mScroller.getCurrY();
        if (oldX != x || oldY != y) {
            scrollTo(x, y);
            if (x != oldX) {
                pageScrolled(x);
            }
        }
    }
    .....省略部分代碼
}

這裡主要注意下面這個判斷,通過查閱各個版本的源碼,發現只有在api23以上才有這個判斷

if (x != oldX) {
      pageScrolled(x);
}

而這個判斷就是回調onPageScrolled方法的。所以答案就出來了:假如不是api23的手機,如果scroller已經finish狀態(動畫的時間到),而view還沒來得及完全刷新,就會走到completeScroll方法,而這時api23以下的手機不回回調onPageScrolled方法。

問題總結
ViewPager的onPageScrolled方法比較不可靠,如果有一些比較關鍵的代碼要放在這裡處理最好改用其它方式實現,不然穩定性不高,容易出問題。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved