ViewPager學(xué)習(xí)(1) - transformer 頁(yè)面切換

做為我viewpager的第一篇,我覺(jué)得說(shuō)一說(shuō)這個(gè)頁(yè)面變換還是很對(duì)頭的,這個(gè)頁(yè)面變換可是我們精通viewpager必會(huì)的第一項(xiàng)

何為頁(yè)面切換效果,就是我們滑動(dòng)viewpager時(shí)當(dāng)前頁(yè)和下一頁(yè)以什么樣式呈現(xiàn),廢話不多說(shuō),先來(lái)看下效果圖:


ezgif.com-video-to-gif.gif

實(shí)現(xiàn)原理:

大家看著像是用動(dòng)畫(huà)實(shí)現(xiàn)的,其實(shí)很簡(jiǎn)單,google已經(jīng)給我們做好準(zhǔn)備了,實(shí)現(xiàn) ViewPager.PageTransformer 這個(gè)接口,然后把這個(gè)實(shí)現(xiàn)對(duì)象設(shè)置到viewpager里即可。


// 這是實(shí)現(xiàn)頁(yè)面切換接口的實(shí)現(xiàn)類類
public class AlpheScaleTransformer implements ViewPager.PageTransformer {

      @Override
    public void transformPage(View page, float position) {
      ....
    }

}

// 然后把這個(gè)實(shí)現(xiàn)對(duì)象設(shè)置到viewpager里
 mViewPager.setPageTransformer(true, new AlpheScaleTransformer());

看著是不是很簡(jiǎn)單啊,其實(shí)細(xì)細(xì)想來(lái),這和實(shí)現(xiàn)動(dòng)畫(huà)是一個(gè)原理。何為動(dòng)畫(huà),快速切換的靜態(tài)圖片罷了,在我們切換viewpager頁(yè)面時(shí),頁(yè)面隨著手指滾動(dòng),滾動(dòng)一次,viewpager就會(huì)調(diào)一次 ViewPager.PageTransformer 這個(gè)接口實(shí)現(xiàn)類來(lái)重置當(dāng)前頁(yè)和下一頁(yè)的樣式,在這里我們做縮放,透明度等各種變換來(lái)操作view的各種屬性,然后隨著系統(tǒng)16ms刷新一幀,也就成了我們看到的樣子。google已經(jīng)提供了這個(gè)接口,而且還放出了官方的demo,所以大家不要怕,這個(gè)切換的知識(shí)點(diǎn)很簡(jiǎn)單的,所以我再viewpager的第一篇才來(lái)說(shuō)這塊。

google官方demo:

package com.example.zb.bloodcrownviewpagertransformer.transformer;

import android.support.v4.view.ViewPager;
import android.view.View;

public class GooglePageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View page, float position) {
        int pageWidth = page.getWidth();

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            page.setAlpha(0);

        } else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);

        } else if (position <= 1) { // (0,1]
            // Fade the page out.
            page.setAlpha(1 - position);

            // Counteract the default slide transition
            page.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            page.setAlpha(0);
        }
    }
}

我的實(shí)現(xiàn):

 public class AlpheScaleTransformer implements ViewPager.PageTransformer {

    private float minAlphe = 0.3f;
    private float minScale = 0.7f;

    @Override
    public void transformPage(View page, float position) {

        if (position < -1 || position > 1) {
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
            return;
        }

        if (position >= -1 && position <= 0) {
            return;
        }

        if (position > 0 && position <= 1) {
            page.setAlpha(minAlphe + (1 - minAlphe) * (1 - Math.abs(position)));
            page.setScaleX(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setScaleY(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setPivotX(page.getWidth() / 2);
            page.setPivotY(page.getHeight() / 2);
            page.setTranslationX(page.getWidth() * -position);
        }
    }
}

實(shí)現(xiàn)要點(diǎn)

目標(biāo)接口:

public class AlpheScaleTransformer implements ViewPager.PageTransformer {

      @Override
    public void transformPage(View page, float position) {
      ....
    }

}

上面的熱鬧看完了,那么我們來(lái)具體的說(shuō)下實(shí)現(xiàn)的要點(diǎn):

  • 接口參數(shù)介紹
  • 接口被誰(shuí)調(diào)用,調(diào)用次數(shù)
  • 結(jié)合實(shí)際理解接口參數(shù)

接口參數(shù)介紹

ViewPager.PageTransformer 接口里面只有一個(gè)方法,用來(lái)不停刷新頁(yè)面樣式的。那么我們觀看里面的 transformPage 這個(gè)方法,參數(shù)是一個(gè)view和一個(gè)數(shù)值。view自然是viewpager的每個(gè)頁(yè)面了,position則是當(dāng)前這個(gè)view頁(yè)面所處的位置。

接口被誰(shuí)調(diào)用,調(diào)用次數(shù)

那么大伙想一想我們滑動(dòng)viewpager時(shí)是幾個(gè)頁(yè)面在動(dòng)?咱就說(shuō)一般的viewpager,那么發(fā)生變化的頁(yè)面一個(gè)是當(dāng)前頁(yè),一個(gè)是下一頁(yè)或是上一頁(yè)啦,那么算下來(lái)就是2個(gè)頁(yè)面,就是2個(gè)view啦。這么說(shuō)的話2個(gè)頁(yè)面都是同時(shí)再運(yùn)動(dòng),那么 transformPage(View page, float position) 這個(gè)方法必然也是會(huì)被調(diào)用多次了。會(huì)調(diào)用幾次,被誰(shuí)調(diào)用?也許大家會(huì)猜測(cè)是參與運(yùn)動(dòng)變化的這2個(gè)頁(yè)面。經(jīng)過(guò)測(cè)試發(fā)現(xiàn)不僅僅是這2個(gè)頁(yè)面會(huì)調(diào)用這個(gè)接口方法,而是viewpager適配器中所有緩存的view都會(huì)調(diào)用這個(gè)接口方法,大家想過(guò)沒(méi)有,為什么會(huì)是這樣,因?yàn)関iewpager不知道緩存的view是不是正在顯示,所以干脆緩存的所有view都去做頁(yè)面變換,萬(wàn)一都在顯示呢,舉個(gè)例子,大家都看過(guò)同時(shí)顯示3個(gè)view的viewpager吧

結(jié)合實(shí)際理解接口參數(shù)

transformPage(View page, float position) 里面就2個(gè)參數(shù),view大家都明白了吧,每個(gè)緩存的view都會(huì)跑一次這個(gè)方法。position比較麻煩也是這個(gè)方法的核心,所以要重點(diǎn)細(xì)說(shuō)。上面說(shuō)position是描述頁(yè)面所處的位置,在開(kāi)始變換前,中間的頁(yè)面(也是當(dāng)前頁(yè)面)position是0,左邊的頁(yè)面position是-1,右邊的頁(yè)面position是1。記住中間頁(yè)面position永遠(yuǎn)是0,整數(shù)表示當(dāng)前頁(yè)右邊的頁(yè),負(fù)數(shù)表示當(dāng)前頁(yè)左邊的頁(yè)

舉個(gè)例子,當(dāng)前頁(yè)是第二頁(yè),我們左滑,實(shí)際是第二頁(yè)往左運(yùn)動(dòng)到手機(jī)盡頭不顯示,第三頁(yè)從右邊慢慢進(jìn)入到手機(jī)屏幕代替第二頁(yè)的位置。postion的變化:

  • 第二頁(yè)(原當(dāng)前頁(yè)) 0 ~ -1
  • 第三頁(yè)1 ~ 0

第二頁(yè)從當(dāng)前頁(yè)運(yùn)動(dòng)到屏幕左側(cè),所以是 從0 ~ -1 的變化。
第三頁(yè)因?yàn)槭窃诘诙?yè)的右邊,所以是 從1 ~ 0的變化。

大家想想是不是這樣,整數(shù)表示右邊,第三頁(yè)的確是在第二頁(yè)的右邊,所以第三頁(yè)開(kāi)始position是1 ,中間的當(dāng)前頁(yè)因?yàn)槭莗osition0,所以第三頁(yè)運(yùn)動(dòng)到屏幕中間代碼第二頁(yè)時(shí),position就是0啦。第二頁(yè)呢因?yàn)槭侵虚g頁(yè),開(kāi)始position是0,第二頁(yè)向左運(yùn)動(dòng),因?yàn)榈诙?yè)在第三頁(yè)的左邊,所以運(yùn)動(dòng)結(jié)束時(shí)是-1。

大家來(lái)看張position變換的表:(這張圖是我扒來(lái)的)


獵豹截圖20170901013453.png

看上面這張圖,基本說(shuō)明了position的數(shù)值范圍,position都是以1做為整數(shù)變更的,0是中間頁(yè)面,-1是左邊的頁(yè)面,那么-2就是左邊的左邊,正數(shù)同理。一般viewpager的頁(yè)面切換至涉及到2個(gè)頁(yè)面,取值 < -1的,> 1的一般都是不可見(jiàn)的頁(yè)面,負(fù)數(shù)都是表示左邊的頁(yè)面或是往左邊一棟的頁(yè)面,正數(shù)表示右邊的頁(yè)面或是往右邊一棟的頁(yè)面,這就是viewpager頁(yè)面切換的核心,參透position參數(shù)的變化,說(shuō)道這里大伙看看上面google的官方實(shí)現(xiàn)或是我的現(xiàn)實(shí)都可以,我的實(shí)現(xiàn)里position < -1 的我都沒(méi)有操作,所以在效果圖里,左邊的頁(yè)面除了默認(rèn)的位移什么效果都沒(méi)有,變化都是來(lái)自于右邊就是因?yàn)閜osition的取舍。默認(rèn)都是會(huì)帶上位移的,我們給view一個(gè)反向的位移就可以讓view實(shí)現(xiàn)在原地變換的效果了。

 if (position > 0 && position <= 1) {
            page.setAlpha(minAlphe + (1 - minAlphe) * (1 - Math.abs(position)));
            page.setScaleX(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setScaleY(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setPivotX(page.getWidth() / 2);
            page.setPivotY(page.getHeight() / 2);
            page.setTranslationX(page.getWidth() * -position);  // 這行就是加一個(gè)反響的位移
        }

總結(jié)

上面我就是說(shuō)了下position的數(shù)值變化,其他的沒(méi)怎么說(shuō),各位看官要是理解的不是很透的話請(qǐng)看參考資料,尤其是參考資料里 transformer 變換的庫(kù)(ViewPagerTransforms),transformer變化的核心都在這些transformer的實(shí)現(xiàn)類上面了。

另外我們?cè)谧约河?jì)算view屬性變換的公式時(shí),只要計(jì)算好一個(gè)方向的公式就好了,反方向postion的數(shù)值會(huì)走反向變化。

項(xiàng)目地址


參考資料


第三方變換庫(kù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容