天天看點

關于ViewPager.PageTransformer的一些了解

今天早上在看hongyang的推送,說已經有了ViewPager2,是google的sample,位址為:https://github.com/googlesamples/android-viewpager2

裡面的動畫我看了一下,還是比較可以的,可以看下面動圖:

關于ViewPager.PageTransformer的一些了解

大概看了一下源碼,動畫是由

ViewPager2.PageTransformer

,其實跟

ViewPager.PageTransformer

接口一緻,然後查閱了一下資料,也算複習一下這個接口吧。

這個接口主要為:

public interface PageTransformer {
    
        void transformPage(@NonNull View page, float position);
    }
           

其中存在兩個參數,比較不好了解,第一個參數page我們可以了解為我們即将要轉換的對象,而對于position,我剛開始的了解為page的的目前的位置index,當看到postion是float的時候,我想我猜錯了。

雖然我不知道這個position是什麼意思,給的解釋也是模棱兩可的,然後我就打log記錄這個position值,大緻得出這樣的結論:

大緻的viewpager效果如下圖:

關于ViewPager.PageTransformer的一些了解

那麼在滑動的過程中:

前一個view的position變化 目前view的position變化 後一個view的position變化
目前view右滑時 -1 ----> 0 0-------->1 1 ----> +∞
目前view左滑時 -∞ ----> -1 0 -----> -1 1 ------->0

我們用動圖模拟一下此時的三個view的position的動态變化:

當我們向右移動時:

關于ViewPager.PageTransformer的一些了解

當我們向左移動時:

關于ViewPager.PageTransformer的一些了解

我們模拟viewpager的滑動,此時可以看到三個position的趨勢與上表是一緻的,是以對于這個position我可以這樣解釋:

目前我們的viewpager存在一個currentItem,就是目前的current position位置,我們記錄此時的坐标軸為0,那麼向右移動時,前一個view的position也是像右移動的,隻是它的坐标是由-1慢慢變大到0的,這種position的值是一個相對值,是相對于目前curerntItem的坐标位置的相對值;同理右邊的view也會向右移動,隻是它的相對值由1慢慢變得無限大。

同理,我們往左滑動時,這個position也是一個有方向的相對值。

還記得我們比較喜歡設定

viewpager.setOffscreenPageLimit

,它的意思就是螢幕之外的view保留幾個,我們也稱之為緩存view,其實這個limit的個數

limitN

與viewpager應該保持view的

Count

的關系為:

即需要viewPager儲存(limitN * 2 + 1)個緩存狀态view。為什麼扯到這個東西呢?很簡單,如果我們将

setOffscreenPageLimit

設定為2,那麼

這個方法中将會有5中不同的資料回調,分别是:

關于ViewPager.PageTransformer的一些了解

我們做個測試,将view加上id:

@NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            ImageView iv = new ImageView(getApplicationContext());
            iv.setScaleType(ImageView.ScaleType.FIT_XY);
            
           	// 将id設定為 10000 + 目前的position
            iv.setId(10000 + position);
            
            ImageUtils.loadImage(imageList.get(position),iv);
            container.addView(iv);

            return iv;
        }
           

然後我們在滑動的時候,列印一下日志:

@Override
    public void transformPage(@NonNull View page, float position) {
        Log.e("TAG", "page:" + page.getId() + "," + position);
    }
           
關于ViewPager.PageTransformer的一些了解

我們看到的确存在5個類型的page值,說明我們的推斷是正确的。

我想我已經說清楚了這個position的位置,了解了這個數值的含義之後,我們來做個簡單的聯系,在滑動的過程中,viewpager的view透明度發生變化:

關于ViewPager.PageTransformer的一些了解

來看核心代碼,其實非常簡單:

@Override
    public void transformPage(@NonNull View page, float position) {
   
        float alpha = 0.0f;
        if(0.0f <= position && position <= 1) {  //1
            alpha = 1.0f - position;
        }else if (-1.0f <= position && position < 0.0f){   //2
            alpha = position + 1.0f ;
        }

        page.setAlpha(alpha);
    }
           

解釋如下:

我們隻考慮兩個view的透明度,是以隻需要考慮postion在 [-1. 1]的情況,而對于向左滑動時,目前的view的position的變化趨勢是由0 —> -1的,是以它走的是

2

中的if語句,postion的絕對值越變越大,是以

alpha = position + 1.0f

越來越小,是以它就越來越透明了;我們需要的下一個next view的alpha的值會越來越大,是以它會越來越不透明了。

現在來一個比較複雜的一點的動畫模式:

關于ViewPager.PageTransformer的一些了解

這個動畫主要有位移、透明度、還有縮放動畫,算上去比較複雜了吧。也還是來看一下比較源碼:

1    @Override
2   public void transformPage(@NonNull View page, float position) {
3        int pagerWidth = boundViewPager.getWidth();
4        float horizontalOffsetBase = (pagerWidth - pagerWidth * CENTER_PAGE_SCALE) / 2;
5
6        if (position >= offscreenPageLimit || position <= -1) {
7            page.setVisibility(View.GONE);
8        } else {
9            page.setVisibility(View.VISIBLE);
10        }
11
12        if (position >= 0) {
13            float translationX = (horizontalOffsetBase - page.getWidth()) * position;
14            page.setTranslationX(translationX);
15        }
16
17        if (position > -1 && position < 0) {
18            float rotation = position * 30;
19            page.setRotation(rotation);
20            page.setAlpha((position * position * position + 1));
21
22        } else if (position > offscreenPageLimit) {
23            page.setAlpha((float) (1 - position + Math.floor(position)));
24
25        } else {
26            page.setRotation(0);
27            page.setAlpha(1);
28        }
29
30
31        if (position == 0) {
32            page.setScaleX(CENTER_PAGE_SCALE);
33            page.setScaleY(CENTER_PAGE_SCALE);
34        } else {
35            float scaleFactor = Math.min(CENTER_PAGE_SCALE - position * 0.1f, CENTER_PAGE_SCALE);
36            page.setScaleY(scaleFactor);
37            page.setScaleY(scaleFactor);
38        }
39 }
           

上面的 boundViewPager就是我們傳入的viewpager,主要的作用就是擷取limitpage,CENTER_PAGE_SCALE我設定的是0.8f.下面開始分析一下:

  1. 從第6行開始 主要是隻顯示offscreenPageLimit + 1個view,其他的view都隐藏掉。
  2. 第12行主要是設定下一個view的位移動畫,使它慢慢向左偏移,這個很好了解。
  3. 第17行主要是我要實作翻頁的效果的動畫,主要時設定目前頁的旋轉動畫和透明度動畫。
  4. 第31行開始,主要就是設定view的縮放動畫了。

從這裡看,設定這種動畫還是比較容易的,隻要你分開去分析,去做,應該是很簡單的。

對于這個PageTransformer,基本原理大家都知道了。其實它還可以做一些比較好看的動畫,我在網上摘了一些,供自己做個筆記吧:

關于ViewPager.PageTransformer的一些了解

&nbsbp;

關于ViewPager.PageTransformer的一些了解

這是這篇文章來的,大牛寫的非常好,大家可以參考一下:

https://blog.csdn.net/u012702547/article/details/52334161

還有github上面開源的庫:

關于ViewPager.PageTransformer的一些了解
關于ViewPager.PageTransformer的一些了解

這個庫來自大神:https://github.com/OCNYang/PageTransformerHelp 他給出的效果有很多,了解了這個position,相信大家會很快了解每個PageTransformer的作用。大家可以去star一下。?

好了,也寫了好長時間了,有不足的地方希望大家指出。

參考文章:

  1. https://blog.csdn.net/u012702547/article/details/52334161
  2. https://blog.csdn.net/shedoor/article/details/78957852
  3. http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1030/1870.html
  4. https://www.cnblogs.com/lang-yu/p/6082791.html
  5. https://www.cnblogs.com/prophet-it/p/7544673.html