ViewPager預(yù)加載莲绰、懶加載和禁止左右滑動(dòng)

此筆記主要是說一下ViewPager如何實(shí)現(xiàn)預(yù)加載欺旧,以及如何實(shí)現(xiàn)懶加載、禁止左右滑動(dòng)蛤签。

  • ViewPager 作為平時(shí)開發(fā)時(shí)經(jīng)常使用的控件辞友,我們多是配合TabLayout、嵌套Fragment使用震肮。

預(yù)加載

  • 當(dāng)ViewPager中嵌套的Fragment多于2個(gè)的時(shí)候称龙,ViewPager就會(huì)預(yù)加載當(dāng)前顯示Fragment左右兩側(cè)的Fragment。

ViewPager是如何實(shí)現(xiàn)預(yù)加載的戳晌?

翻看ViewPager我們可以發(fā)現(xiàn)一個(gè)常量 private static final int DEFAULT_OFFSCREEN_PAGES = 1; 其實(shí)鲫尊,這就是實(shí)現(xiàn)ViewPager預(yù)加載的值,這個(gè)值的意義也是 默認(rèn)ViewPager當(dāng)前變量的值為1沦偎。

那么ViewPager具體是如何實(shí)現(xiàn)的呢疫向?繼續(xù)翻看源碼。

ViewPager源碼中全局搜查 DEFAULT_OFFSCREEN_PAGES豪嚎,發(fā)現(xiàn)將 DEFAULT_OFFSCREEN_PAGES 賦值給了 mOffscreenPageLimit 搔驼,那我們繼續(xù)搜查 mOffscreenPageLimit ,發(fā)現(xiàn) 又賦值給了 pageLimit 疙渣,好了匙奴,我們終于找到了我們要看的邏輯。源碼中我們發(fā)現(xiàn)妄荔,通過當(dāng)前的Item與pageLimit計(jì)算左右需要預(yù)加載頁面的角標(biāo)泼菌。

計(jì)算的方法如下:


    final int startPos = Math.max(0, mCurItem - pageLimit);
    final int N = mAdapter.getCount();
    final int endPos = Math.min(N - 1, mCurItem + pageLimit);

好了谍肤,我們來模擬一下,假設(shè)此時(shí)ViewPager中有10個(gè)頁面哗伯,當(dāng)前頁面為3荒揣。pageLimit = mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES = 1;

    startPos = Math.max(0 , 3 - 1); = Math.max(0 ,2); = 2;
    n = 10;
    endPos = Math.min(10 - 1 , 3 + 1); = Math.min(9 , 4); = 4;

    也就是說:

    startPos = 2;
    n = 10;
    endPos = 4;

    這樣就實(shí)現(xiàn)了ViewPager的預(yù)加載功能。

懶加載

ViewPager如何實(shí)現(xiàn)懶加載焊刹?

  • 上面我們分析了ViewPager是如何實(shí)現(xiàn)預(yù)加載的系任,可是有時(shí)我們不想實(shí)現(xiàn)ViewPager的預(yù)加載功能,因?yàn)橛脩艨赡懿粫?huì)查看預(yù)加載的頁面就退出了虐块,而且預(yù)加載的頁面如果有聯(lián)網(wǎng)操作俩滥,也會(huì)消耗用戶的流量。
  • 那么贺奠,我們?nèi)绾螌?shí)現(xiàn)懶加載呢霜旧?

別怕,上面我們既然找到了ViewPager如何實(shí)現(xiàn)預(yù)加載的方法儡率,我們可以修改 DEFAULT_OFFSCREEN_PAGES = 0 挂据,使其不實(shí)現(xiàn)預(yù)加載。我們可以驗(yàn)證一下:


    final int startPos = Math.max(0, mCurItem - pageLimit);
    final int N = mAdapter.getCount();
    final int endPos = Math.min(N - 1, mCurItem + pageLimit);

同樣儿普,還假設(shè)ViewPager中有10個(gè)頁面崎逃,當(dāng)前頁面為第3個(gè)。pageLimit = mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES = 0;

    startPos = Math.max(0 , 3 - 0); = Math.max(0 ,3); = 3;
    n = 10;
    endPos = Math.min(10 - 1 , 3 + 0); = Math.min(9 , 3); = 3;

    也就是說:

    startPos = 3;
    n = 10;
    endPos = 3;

    這樣就實(shí)現(xiàn)了ViewPager的懶加載功能眉孩。

但是 DEFAULT_OFFSCREEN_PAGES =1; 是ViewPager中默認(rèn)的值个绍,即便是我們打開ViewPager的源碼將其修改為0,運(yùn)行后還是默認(rèn)為1 勺像,我們?nèi)绻獙?shí)現(xiàn)懶加載障贸,只有將 ViewPager 下的代碼完全復(fù)制一份错森,然后自建一LazyViewPager 繼承于ViewGroup吟宦,然后將代碼粘貼過來,并將 DEFAULT_OFFSCREEN_PAGES 的值修改為0即可涩维,使用的時(shí)候殃姓,直接使用LazyViewPager即可。

ViewPager禁止左右滑動(dòng)

ViewPager如何禁止左右滑動(dòng)瓦阐?

  • 我們在使用ViewPager的時(shí)候一般里面嵌套的Fragment會(huì)使用ListView或者RecyclerView 亦或者有輪播圖蜗侈,但是在左右滑動(dòng)的時(shí)候是輪播圖滑動(dòng)呢還是讓ViewPager左右滑動(dòng)呢?
  • 這個(gè)時(shí)候我們就要禁止ViewPager的左右滑動(dòng)操作睡蟋。我們?nèi)绾尾僮髂兀?/li>

其實(shí)禁止ViewPager的左右滑動(dòng)也很簡單踏幻,從事件分發(fā)機(jī)制考慮即可。翻看ViewPager的 onInterceptTouchEvent 方法戳杀,也可以看到注釋:

public boolean onInterceptTouchEvent(MotionEvent ev){
    /*
     * This method JUST determines whether we want to intercept thmotion.
     * If we return true, onMotionEvent will be called and we do thactual
     * scrolling there.
     */
 
    ...
 }

什么意思呢该面?大概意思是說:這個(gè)方法決定了我們是否要截?cái)鄤?dòng)作夭苗。如果返回true,onMotionEvent將被調(diào)用,我們在那里執(zhí)行實(shí)際的滾動(dòng)隔缀。

所以题造,我們可以大概理解為:是否要攔截事件,如果攔截就自己處理猾瘸,如果不攔截就將事件傳遞給下面的子View處理界赔。我們可以發(fā)現(xiàn),此方法返回的是boolean類型牵触,所以淮悼,我們要禁止左右滑動(dòng)的話,只需要返回false即可揽思,意思就是不攔截事件敛惊,傳遞給下面的子View。

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
    }
  • 但是如果viewpage里面子控件不是viewgroup,還是會(huì)調(diào)用 onTouchEvent 方法绰更,所以瞧挤,我們還要處理onTouchEvent這個(gè)方法汞幢。

查看ViewPager的onTouchEvent發(fā)現(xiàn)母赵,喔,里面處理的邏輯好多荆秦,看的頭蒙徐钠,怎么辦呢癌刽?不用急,簡單的說此方法大概意思是:是否自己消費(fèi)事件尝丐。如果自消費(fèi)显拜,事件就結(jié)束。如果不消費(fèi)就傳遞給父控件爹袁。所以远荠,我們想實(shí)現(xiàn)禁止左右滑動(dòng),只需要ViewPager不消費(fèi)事件即可:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return false;
    }

綜上所述失息,如果我們想實(shí)現(xiàn)ViewPager的禁止左右滑動(dòng)譬淳,只要覆寫 onInterceptTouchEvent 方法 和 onTouchEvent 方法即可。

  • 如果考慮復(fù)用盹兢,即使用同一個(gè)ViewPager 邻梆,有時(shí)可以左右滑動(dòng),有時(shí)禁止绎秒,那么我們可以寫一個(gè)方法讓其實(shí)現(xiàn)是否可以左右滑動(dòng)浦妄。
    public void setNoScroll(boolean noScroll) {
        mNoScoll = noScroll;
    }
    

然后在 onTouchEvent 方法和 onInterceptTouchEvent方法判斷處理即可:

 @Override
    public boolean onTouchEvent(MotionEvent ev) {

        if (mNoScoll) {
            return false;
        } else {
            return super.onTouchEvent(ev);
        }


    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (mNoScoll) {
            return false;
        } else {
            return super.onInterceptTouchEvent(ev);
        }
    }

簡單說一下,mNoScoll 默認(rèn)false ,如果我們現(xiàn)在的ViewPager 不想實(shí)現(xiàn)左右滑動(dòng)剂娄,只需要 setNoScroll(true) 即可窘问,此時(shí)mNoScoll 為false,然后在 onTouchEvent 方法和 onInterceptTouchEvent 方法的時(shí)候已經(jīng) 攔截 和 不消費(fèi)了宜咒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惠赫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子故黑,更是在濱河造成了極大的恐慌儿咱,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件场晶,死亡現(xiàn)場離奇詭異混埠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)诗轻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門钳宪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扳炬,你說我怎么就攤上這事吏颖。” “怎么了恨樟?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵半醉,是天一觀的道長。 經(jīng)常有香客問我劝术,道長缩多,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任养晋,我火速辦了婚禮衬吆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绳泉。我一直安慰自己逊抡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布圈纺。 她就那樣靜靜地躺著秦忿,像睡著了一般麦射。 火紅的嫁衣襯著肌膚如雪蛾娶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天潜秋,我揣著相機(jī)與錄音蛔琅,去河邊找鬼。 笑死峻呛,一個(gè)胖子當(dāng)著我的面吹牛罗售,可吹牛的內(nèi)容都是我干的辜窑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寨躁,長吁一口氣:“原來是場噩夢啊……” “哼穆碎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起职恳,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤所禀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后放钦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體色徘,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年操禀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了褂策。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颓屑,死狀恐怖斤寂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情揪惦,我是刑警寧澤扬蕊,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站丹擎,受9級(jí)特大地震影響尾抑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蒂培,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一再愈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧护戳,春花似錦翎冲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钳枕,卻和暖如春缴渊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鱼炒。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工衔沼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓指蚁,卻偏偏與公主長得像菩佑,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子凝化,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,095評(píng)論 25 707
  • 2017年05月30 最后的懶加載寫的不好稍坯,推薦請(qǐng)叫我大蘇同學(xué)寫的Fragment懶加載博客,【Android】再...
    英勇青銅5閱讀 13,410評(píng)論 56 189
  • 絲絲小雨臨江南搓劫,潤色多少閑庭館劣光。 百年老屋人何在?歲月變換如云煙糟把。
    綠野V仙蹤閱讀 230評(píng)論 4 4
  • 那一年 我廢寢忘食 夜以繼日 也未能走上理想的求學(xué)之路 那一年 我不顧父母的反對(duì)绢涡,與家人僵持到底 也要堅(jiān)持走自己認(rèn)...
    影落寒溪閱讀 184評(píng)論 0 1
  • 0. 背景Android 6.0 (API level 23)中,將權(quán)限分成了兩類遣疯。 一類是Install權(quán)限(稱...
    天空在微笑閱讀 2,203評(píng)論 0 4