1.介绍 ① PageTransformer接口
ViewPager提供了PageTransformer接口用于实现翻页动画。有两个参数:page 和 position。
1 2 3 4 public interface PageTransformer { void transformPage (@NonNull View page, float position) ; }
② position的理解
如果超过屏幕的绝对距离超过屏幕的宽度,那么绝对距离就会变成无限大。仔细想想,只有page 的 position 处于 ( -1 , 1 ) 的位置,我们才能在屏幕看到它们的内容。
上面的理解是来自别人博客的理解,这样子理解有点小问题。我在自己实现 PageTransformer接口 的时候,在函数里面打印了 position 。
如果你有六个页面,由于ViewPager默认只会加载两个页面,所以只会有第一个页面和第二个页面进入到我们的 transformPage 方法中,position 的值依次是 0.0 和 1.0。这样子,我们就不能对其他的页面进行动画,毕竟其他的页面不进来这个方法中。
当你位于第一个页面时,如果想要滑到第二个页面。此时变化的只有第一个页面和第二个页面的 position。第一个页面的 position 从 0.0 -> -1.0,第二个页面的 position 从 1.0 -> 0.0。此时,第三个页面仍然不会进入 transformPage 方法中。
但是,如果我们设置默认加载的页面是6个,会怎么样呢?看到下面的打印结果我们终于解开了疑惑,也知道了该怎么对其他页面进行动画了,也知道了之前的错误。超过屏幕的绝对距离超过屏幕的宽度,那么绝对距离不会变成无限大,而是慢慢累加的。同理,反方向也不是无限大,而是 -1.0 , -2.0 等等
1 2 3 4 5 6 position:0.0 + Page:android.widget.LinearLayout{b42dbdb V.E...... ......ID 0 ,0 -1080 ,1730 } position:1.0 + Page:android.widget.LinearLayout{d68678 V.E...... ......ID 1080 ,0 -2160 ,1730 } position:2.0 + Page:android.widget.LinearLayout{1200151 V.E...... ......ID 2160 ,0 -3240 ,1730 } position:3.0 + Page:android.widget.LinearLayout{ad6db6 V.E...... ......ID 3240 ,0 -4320 ,1730 } position:4.0 + Page:android.widget.LinearLayout{2095ab7 V.E...... ......ID 4320 ,0 -5400 ,1730 } position:5.0 + Page:android.widget.LinearLayout{8299224 V.E...... ......ID 5400 ,0 -6480 ,1730 }
③ 使用方式
1 2 public void setPageTransformer (boolean reverseDrawingOrder, @Nullable PageTransformer transformer)
参数reverseDrawingOrder: true表示提供的PageTransformer画view时是倒序,false则是正序。不理解的可以看接下里的gif图。
参数transformer: 就是我们 PageTransformer接口 的实现对象啦。
2. 官方例子:DepthPageTransformer
从小猫切换到小狗的过程中:
对于 position 处于 [-1,0] 的页面(小猫),不设置透明度,缩放,平移动画。
对于 position 处于 [0,1] 的页面(小狗),设置透明度,缩放,平移动画,平移动画用来让视图一直处于屏幕位置。因为默认情况下处于 [0,1] 的页面 是一步一步平移到屏幕位置的,我们使用平移动画让它一直处于屏幕位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 pager.setPageTransformer(true , new DepthPageTransformer()); public class DepthPageTransformer implements ViewPager .PageTransformer { private static final float MIN_SCALE = 0.75f ; @Override public void transformPage (@NonNull View page, float position) { int pageWidth = page.getWidth(); if (position < -1 ) { page.setAlpha(0 ); } else if (position <= 0 ) { page.setAlpha(1 ); page.setTranslationX(0 ); page.setScaleX(1 ); page.setScaleY(1 ); } else if (position <= 1 ) { page.setAlpha(1 - position); page.setTranslationX(pageWidth * -position); float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); } else { page.setAlpha(0 ); } } }
我们之前的效果是设置 true,倒序绘图。我们改成 false 正序后的效果如下:
3. 官方例子:ZoomOutPageTransformer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 pager.setPageTransformer(true , new ZoomOutPageTransformer()); public class MainActivity extends AppCompatActivity { @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewPager pager = findViewById(R.id.pager); TabLayout tab = findViewById(R.id.tab); List<Fragment> fragments = new ArrayList<>(); fragments.add(new MyFragment1()); fragments.add(new MyFragment2()); String[] titles = getResources().getStringArray(R.array.title); pager.setAdapter( new MyAdapterFragment( getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT, fragments, titles ) ); tab.setupWithViewPager(pager); pager.setPageTransformer(true , new ZoomOutPageTransformer()); } }
二. 自定义翻页动画 1. 旋转翻页动画
自定义的播放动画类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public class RotationTransformer implements ViewPager .PageTransformer { @Override public void transformPage (@NonNull View page, float position) { float margin = 40 ; int width = page.getWidth(); page.setTranslationX(-width * (position)); page.setTranslationY(-position * margin); if (position > 0.0f ) { page.setPivotX(0 ); page.setPivotY(0 ); page.setRotation(0f ); }else if (position >= -0.1f && position <= 0.0f ) { page.setPivotX(0 ); page.setPivotY(0 ); page.setRotation(-180f * position); }else { page.setPivotX(0 ); page.setPivotY(0 ); page.setRotation(180f ); } } }
注意:setOffscreenPageLimit设置的预加载数量一定要是:页面的数量。不然的话页面的垂直偏移不会全部社会成功。因为我们每次的动画范围都涉及到所有的页面,需要所有的页面都需要进入到 transformPage 方法中。
2.缩放翻页动画
自定义的播放动画类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ScaleTransformer implements ViewPager .PageTransformer { @Override public void transformPage (@NonNull View page, float position) { if (position >= -1.0f && position <= 0.0f ) { page.setScaleX(1 + position * 0.1f ); page.setScaleY(1 + position * 0.2f ); } else if (position > 0.0f && position <= 1.0f ) { page.setScaleX(1 - position * 0.1f ); page.setScaleY(1 - position * 0.2f ); } else { page.setScaleX(0.9f ); page.setScaleY(0.8f ); } } }
注意:这个时候因为ViewPager默认加载的页面是两个,当前的页面和即将划出当前的页面会进入 transformPage 方法中,而我们的每次的动画范围只涉及这两个页面,故对页面加载的数量没有要求。
三. 结合 CardView 实现 参考:CardView 简介和使用
参考:CardView+ViewPager实现ViewPager翻页动画
四. 各种各样的翻页动画 参考:ViewPager 16种切换动画,早晚能用到
参考文章 ViewPager 全面剖析及使用详解
巧用ViewPager实现驾考宝典做题翻页效果