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

做為我viewpager的第一篇,我覺得說一說這個頁面變換還是很對頭的,這個頁面變換可是我們精通viewpager必會的第一項

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


ezgif.com-video-to-gif.gif

實現(xiàn)原理:

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


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

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

}

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

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

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);
        }
    }
}

我的實現(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);
        }
    }
}

實現(xiàn)要點

目標(biāo)接口:

public class AlpheScaleTransformer implements ViewPager.PageTransformer {

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

}

上面的熱鬧看完了,那么我們來具體的說下實現(xiàn)的要點:

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

接口參數(shù)介紹

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

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

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

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

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

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

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

第二頁從當(dāng)前頁運動到屏幕左側(cè),所以是 從0 ~ -1 的變化。
第三頁因為是在第二頁的右邊,所以是 從1 ~ 0的變化。

大家想想是不是這樣,整數(shù)表示右邊,第三頁的確是在第二頁的右邊,所以第三頁開始position是1 ,中間的當(dāng)前頁因為是position0,所以第三頁運動到屏幕中間代碼第二頁時,position就是0啦。第二頁呢因為是中間頁,開始position是0,第二頁向左運動,因為第二頁在第三頁的左邊,所以運動結(jié)束時是-1。

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


獵豹截圖20170901013453.png

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

總結(jié)

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

另外我們在自己計算view屬性變換的公式時,只要計算好一個方向的公式就好了,反方向postion的數(shù)值會走反向變化。

項目地址


參考資料


第三方變換庫

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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