PageTransformer是ViewPager内部定义的接口,实现该接口并应用于ViewPager可以控制ViewPager中item view的滑动效果。
接下来我们看一下PageTransformer源码及api介绍,比较简单
/**
* A PageTransformer is invoked whenever a visible/attached page is scrolled.
* This offers an opportunity for the application to apply a custom transformation
* to the page views using animation properties.
*
* <p>As property animation is only supported as of Android 3.0 and forward,
* setting a PageTransformer on a ViewPager on earlier platform versions will
* be ignored.</p>
*/
public interface PageTransformer {
/**
* Apply a property transformation to the given page.
*
* @param page Apply the transformation to this page
* @param position Position of page relative to the current front-and-center
* position of the pager. 0 is front and center. 1 is one full
* page position to the right, and -1 is one page position to the left.
*/
void transformPage(@NonNull View page, float position);
}
该接口就一个方法,在ViewPager滑动过程中会触发该方法,我们主要看下这个方法中的两个参数:
- View page:ViewPager中的页面
-
position:该参数并不是指ViewPager中页面的索引,position是page相对于基准参考点的偏移量,滑动过程中可标识page的偏移程度,周期为1,current page的position为0,上一页的position为-1.0,下一页的position为1.0,依此类推。position随ViewaPger滑动趋势发生相应变化:
向左滑动时,page相对于基准参考点向左偏移,position减小;向右滑动时page相对于基准参考点向右偏移,position变大,其绝对值反应了page与基准参考点间的距离。我们可以根据position的变化,来实现想要的效果。
下面我们具体看下position的变化吧。
mViewPager.setAdapter(adapter = new MyViewPagerAdapter());
mViewPager.setOffscreenPageLimit(4);
mViewPager.setPageTransformer(false, new ViewPager.PageTransformer() {
@Override
public void transformPage(@NonNull View page, float position) {
Log.e("TAG", "页面" + page.getTag() + " position:::" + position);
}
//Log
页面0 position:::0.0
页面1 position:::1.0
页面2 position:::2.0
页面3 position:::3.0
页面4 position:::4.0
在初始化时由于我们设置了setOffscreenPageLimit(4)所以除了当前View之后还会初始化屏幕外的4个View。如果此时向左滑动一直滑动到最后一页的log如下:
页面0 position:::0.0~-1.0~-2.0~-3.0
页面1 position:::1.0~0.0~-1.0~-2.0
页面2 position:::2.0~1.0~0.0~-1.0
页面3 position:::3.0~2.0~1.0~0.0
如果向右滑动到第一页,log如下:
页面0 position:::-3.0~-2.0~-1.0~0.0
页面1 position:::-2.0~-1.0~0.0~1.0
页面2 position:::-1.0~0.0~1.0~2.0
页面3 position:::0.0~1.0~2.0~3.0
通过上面的log我们应该大概清楚了它的规律。下面进入实战,先看下动图。
![](https://img.haomeiwen.com/i7264052/de5366ba6c3d587b.gif)
实现上面的效果主要分为如下几步:
-
如何实现子View的重叠排布。
ViewPager的子View原本是横向排布的,我们可以通过控制子View进行x轴方向的位移实现重叠。
-
如何实现子View的重叠排布。
int pagerWidth = mViewPager.getWidth();
float horizontalOffsetBase = (pagerWidth - pagerWidth *
CENTER_PAGE_SCALE) / 2 / offscreenPageLimit + 45;
float translationX = (horizontalOffsetBase - page.getWidth()) * position;
page.setTranslationX(translationX);
很简单就是让子View平移-positionpage.getWidth()的距离,但是这并不能实现重叠效果,还需要在此基础上向右偏移positionhorizontalOffsetBase 距离才行。实现了这一步的同学肯定会发现此时最上层的View并不是第一个View,下面我们就讲下如何让第一个View在最上层。
-
如何实现最上层的View为首个子View
实现方式有3种:
1.通过 ViewCompat.setTranslationZ(page, (offscreenPageLimit - position) * 5);
2.通过ViewCompat.setElevation(page, (offscreenPageLimit - position) * 5);
3.将mViewPager.setPageTransformer(true, new ViewPager.PageTransformer() )中的第一个参数设置为true即可。
前两种方法的原理一样,都是改变View在z轴上的深度(高度),它们之间的关系是z值=translationZ+elevation,遗憾的是他们只适用于5.0以上。推荐使用第三种方式。
其他的就很简单的,不再赘述。最后奉上完整代码
-
如何实现最上层的View为首个子View
mViewPager.setPageTransformer(true, new ViewPager.PageTransformer() {
@Override
public void transformPage(@NonNull View page, float position) {
int pagerWidth = mViewPager.getWidth();
float horizontalOffsetBase = (pagerWidth - pagerWidth * CENTER_PAGE_SCALE) / 2 / offscreenPageLimit + 45;
if (position >= offscreenPageLimit || position <= -1) {
page.setVisibility(View.GONE);
} else {
page.setVisibility(View.VISIBLE);
}
if (position >= 0) {
float translationX = (horizontalOffsetBase - page.getWidth()) * position;
page.setTranslationX(translationX);
}
if (position > -1 && position < 0) {
float rotation = position * 30;
page.setRotation(rotation);
page.setAlpha((position * position * position + 1));
}else if (position > offscreenPageLimit - 1) {
page.setAlpha((float) (1 - position + Math.floor(position)));
} else {
page.setRotation(0);
page.setAlpha(1);
}
if (position == 0) {
page.setScaleX(CENTER_PAGE_SCALE);
page.setScaleY(CENTER_PAGE_SCALE);
} else {
float scaleFactor = Math.min(CENTER_PAGE_SCALE - position * 0.1f, CENTER_PAGE_SCALE);
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
}
ViewCompat.setElevation(page, (offscreenPageLimit - position) * 5);
}
});
网友评论