关于ViewPager.PageTransformer的一些理解

Posted microhex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于ViewPager.PageTransformer的一些理解相关的知识,希望对你有一定的参考价值。

今天早上在看hongyang的推送,说已经有了ViewPager2,是google的sample,地址为:https://github.com/googlesamples/android-viewpager2
里面的动画我看了一下,还是比较可以的,可以看下面动图:

大概看了一下源码,动画是由ViewPager2.PageTransformer,其实跟ViewPager.PageTransformer接口一致,然后查阅了一下资料,也算复习一下这个接口吧。
这个接口主要为:

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

其中存在两个参数,比较不好理解,第一个参数page我们可以理解为我们即将要转换的对象,而对于position,我刚开始的理解为page的的当前的位置index,当看到postion是float的时候,我想我猜错了。
虽然我不知道这个position是什么意思,给的解释也是模棱两可的,然后我就打log记录这个position值,大致得出这样的结论:
大致的viewpager效果如下图:

那么在滑动的过程中:

前一个view的position变化当前view的position变化后一个view的position变化
当前view右滑时-1 ----> 00-------->11 ----> +∞
当前view左滑时-∞ ----> -10 -----> -11 ------->0

我们用动图模拟一下此时的三个view的position的动态变化:
当我们向右移动时:

当我们向左移动时:

我们模拟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的关系为:

	Count = limitN * 2 + 1

即需要viewPager保存(limitN * 2 + 1)个缓存状态view。为什么扯到这个东西呢?很简单,如果我们将setOffscreenPageLimit设置为2,那么

void transformPage(@NonNull View page, float position);

这个方法中将会有5中不同的数据回调,分别是:

我们做个测试,将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);
    


我们看到的确存在5个类型的page值,说明我们的推断是正确的。

我想我已经说清楚了这个position的位置,了解了这个数值的含义之后,我们来做个简单的联系,在滑动的过程中,viewpager的view透明度发生变化:

来看核心代码,其实非常简单:

   @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的值会越来越大,因此它会越来越不透明了。

现在来一个比较复杂的一点的动画模式:

这个动画主要有位移、透明度、还有缩放动画,算上去比较复杂了吧。也还是来看一下比较源码:

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,基本原理大家都知道了。其实它还可以做一些比较好看的动画,我在网上摘了一些,供自己做个笔记吧:
&nbsbp;

这是这篇文章来的,大牛写的非常好,大家可以参考一下:
https://blog.csdn.net/u012702547/article/details/52334161

还有github上面开源的库:

这个库来自大神: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

以上是关于关于ViewPager.PageTransformer的一些理解的主要内容,如果未能解决你的问题,请参考以下文章

scrapy 关于 rule, 关于多页

JS学习笔记关于选项卡,关于this,关于innerHTML

关于唯典冰淇淋新闻页的布局

关于prototype.js的一些技术说明

主页链接发送到关于/关于页面无法回家

关于写作