利用ViewPage的PagerTransformer定制页面切换效果 您所在的位置:网站首页 三国演义中谁草船借箭 利用ViewPage的PagerTransformer定制页面切换效果

利用ViewPage的PagerTransformer定制页面切换效果

2024-01-31 20:30| 来源: 网络整理| 查看: 265

利用ViewPage的PagerTransformer定制页面切换效果ViewPager动态添加删除及刷新页面ViewPager打造真正意义的无限轮播ViewPage 联动效果自带角标ViewPager禁止滑动和修改滑动速度 1. 简述

你是不是觉得 ViewPager 默认的切换效果有些平淡?其实,我们可以定制 ViewPager 的页面切换效果。定制 ViewPager 的页面切换效果,只需用到 ViewPager 的一个方法setPageTransformer(boolean reverseDrawingOrder, @Nullable PageTransformer transformer),实现一个接口 PageTransformer 。

2. PageTransformer

PageTransformer 是 ViewPager 内部一个接口,源码如下:

/** * 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. * 每当滚动到 可见/附属 页面时,都会调用 PageTransformer 。 * 这为应用程序提供了使用动画属性对页面视图应用自定义转换的机会。 *

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.

*/ 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. * 页面相对于当前正中位置的位置。0代表正中。1 是右边的一个完整页面位置, * -1 是左边的一个页面位置。 */ void transformPage(@NonNull View page, float position); }

从源码注释我们可以看出, PageTransformer 就是为自定义页面切换效果而生的。

使用 PageTransformer 需要实现方法 void transformPage(@NonNull View page, float position),这个方法有两个参数,两个参数是对应关系,position 表示页面相对于正中(0)的位置,0代表正中,1 是右边的一个完整页面位置,-1 是左边的一个页面位置。

如下图所示,ViewPager 页面滑动过程中,屏幕中显示 2 个页面,即左边页面(绿色)的一部分和右边页面(蓝色)的一部分。以虚线和页面左边缘作为位置参考,那么左边页面位置在 (-1, 0) 区间,右边页面位置在 (0, 1) 区间。它们的值是:position左 = (x左 - x0) / width,position右 = (x右 - x0) / width。 在这里插入图片描述 一般情况下我们最多只能看到如上所示两个页面,所以多数情况下,我们可以把 position 分为 3 段。

(-Infinity, -1) :左边不可见页面。[-1, 1]:中间可见页面,其中 [-1, 0) 表示左边可见页面,[0, 1] 表示右边可见页面。(1, +Infinity) :右边不可见页面。 当页面的 position = 0,此页面正中显示。

可以调用 ViewPager 的 setOffscreenPageLimit(int) 方法设置了离屏缓存页面数量(空闲时,当前页面左右保留页面数量)。

如果想在 ViewPager 中显示多个页面,可以:

调用 setOffscreenPageLimit(int) 设置离屏缓存页面数量 大于 1;给 ViewPager 外层控件以及 ViewPager 都设置 android:clipChildren="false";给 ViewPager 设置 适当的 leftMargin 和 rightMargin 。 3. 例子和效果

1、手风琴效果 手风琴效果 其实就是水平缩放效果。在页面滑动时, 左边页面 position < 0,右边页面 position > 0; 左边页面以页面右边缘为缩放中心,右边页面以左边缘为缩放中心。 代码如下所示:

/** * 手风琴效果(水平方向缩放) */ public class AccordionTransformer implements ViewPager.PageTransformer { @Override public void transformPage(@NonNull View page, float position) { if (position page.setPivotX(0f); page.setScaleX(1f - position * 0.5f); } } }

2、下弧形效果 下弧形 实现此效果需以页面下边缘某一点为旋转中心旋转:

position < -1 时,旋转到最大角度,旋转中心为右下角;-1 < position < 0 时,position 越靠近 0 ,旋转角度越小,旋转中心向下边缘中心靠拢;0 page.setPivotY( page.getHeight()); if (position //[-1, 1] if (position //[0, 1] page.setRotation(mMaxRotate * position); page.setPivotX(page.getWidth() * (0.5f - 0.5f * position)); } } else {//(1, +Infinity] page.setRotation(mMaxRotate); page.setPivotX(0f); } } }

3、上弧形效果 上弧形 与下弧形相反,旋转中心以上边缘某一点:

position < -1 时,旋转到最大角度,旋转中心为右下角;-1 < position < 0 时,position 越靠近 0 ,旋转角度越小,旋转中心向上边缘中心靠拢;0 page.setPivotY(0f); if (position //[-1, 1] if (position //[0, 1] page.setRotation(-mMaxRotate * position); page.setPivotX(page.getWidth() * (0.5f - 0.5f * position)); } } else {//(1, +Infinity] page.setRotation(-mMaxRotate); page.setPivotX(0f); } } }

4、立方翻转-外 立方翻转-外 其实是绕 Y 轴旋转,再加上缩放效果。绕 Y 轴旋转,用到了 View 的 setRotationY(float) 方法,此方法可以设置绕 Y 轴的旋转角度。

position < -1,逆时针旋转到最大角度,旋转中心为页面右边缘;-1 this(DEFAULT_MAX_ROTATION); } public CubicOverturnTransformer(float maxRotation) { this(maxRotation, DEF_MIN_SCALE); } public CubicOverturnTransformer(float maxRotation, float minScale) { mMaxRotation = maxRotation; this.mMinScale = minScale; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void transformPage(@NonNull View page, float position) { page.setPivotY(page.getHeight() / 2f); float distance = getCameraDistance(); page.setCameraDistance(distance);//设置 View 的镜头距离,可以防止旋转大角度时出现图像失真或不显示。 if (position // [-1,1] page.setRotationY(position * mMaxRotation); if (position //[1,0] page.setPivotX(0); float scale = DEF_MIN_SCALE + 4f * (1f - DEF_MIN_SCALE) * (position - 0.5f) * (position - 0.5f); page.setScaleX(scale); page.setScaleY(scale); } } else { // (1,+Infinity] page.setRotationY(mMaxRotation); page.setPivotX(0); } } /** * 获得镜头距离(图像与屏幕距离)。参考{@link View#setCameraDistance(float)},小距离表示小视角, * 大距离表示大视角。这个距离较小时,在 3D 变换(如围绕X和Y轴的旋转)时,会导致更大的失真。 * 如果改变 rotationX 或 rotationY 属性,使得此 View 很大 (超过屏幕尺寸的一半),则建议始终使用 * 大于此时图高度 (X 轴旋转)或 宽度(Y 轴旋转)的镜头距离。 * @return 镜头距离 distance * * @see {@link View#setCameraDistance(float)} */ private float getCameraDistance() { DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics(); float density = displayMetrics.density; int widthPixels = displayMetrics.widthPixels; int heightPixels = displayMetrics.heightPixels; return 1.5f*Math.max(widthPixels, heightPixels)*density; } }

使用:

mPageTransformer = new CubicOverturnTransformer(90f, 0.6f); mVpImgs.setPageTransformer(reverseDrawingOrder, mPageTransformer);

最大旋转角度 90 度,最小缩放到 0.6 。

5、立方翻转-内 立方翻转-内

与上一个效果是同一套代码,绕 Y 轴旋转方向相反,使用时,让 最大旋转角度小于 0 即可,如下代码所示,最大旋转角度改为 -90f 就是内部翻转:

使用:

mPageTransformer = new CubicOverturnTransformer(-90f, 0.6f); mVpImgs.setPageTransformer(reverseDrawingOrder, mPageTransformer);

最大旋转角度 90 度,最小缩放到 0.6 。

6、下沉效果 下沉效果

特殊的缩放效果,有最小缩放值,页面缩到最小值不再缩小,同时有透明度的变化(可以去掉透明度变化)。 旋转中心位置的调整主要是为了调整页面间隙。

/** * 下沉效果 */ public class DipInTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.85f; private float mMinScale = MIN_SCALE; private static final float MIN_ALPHA = 0.5f; private float mMinAlpha = MIN_ALPHA; @Override public void transformPage(@NonNull View page, float position) { Log.i("DipInTransformer", "transformPage: id = " + page.getId() + ", position = " + position); int pageWidth = page.getWidth(); int pageHeight = page.getHeight(); // page.setPivotX(pageWidth * 0.5f); page.setPivotY(pageHeight * 0.5f); if (position //(-1, 1) float scaleFactor = Math.max(mMinScale, 1 - Math.abs(position)); page.setScaleX(scaleFactor); page.setScaleY(scaleFactor); if (position page.setPivotX(pageWidth * (0.5f - 0.5f * scaleFactor)); } page.setAlpha(mMinAlpha + (scaleFactor - mMinScale) / (1f - mMinScale) * (1f - mMinAlpha)); } else {//(1, +Infinity) page.setAlpha(mMinAlpha); page.setScaleX(mMinScale); page.setScaleY(mMinScale); page.setPivotX(pageWidth * 0f); } } }

7、淡入淡出效果(透明度) 淡入淡出(透明度) 不多作解释,就是透明度属性动画。代码如下:

/** * 淡入淡出 */ public class FadeInOutTransformer implements ViewPager.PageTransformer { private static final float DEF_MIN_ALPHA =0.5f; private float mMinAlpha = DEF_MIN_ALPHA; @Override public void transformPage(@NonNull View page, float position) { if (position //[-1, 1] if (position //[0, 1] page.setAlpha(1f - (1f - mMinAlpha) * position); } } else {//(1, +Infinity] page.setAlpha(mMinAlpha); } } }

8、水平翻转效果(左右翻转) 左右翻转

即以水平中心线为旋转中心,绕 Y 轴旋转。代码如下所示,同样要注意镜头距离:

/** * 水平翻转效果 */ public class FlipHorizontalTransformer implements ViewPager.PageTransformer { @Override public void transformPage(@NonNull View page, float position) { page.setCameraDistance(getCameraDistance()); page.setTranslationX(-page.getWidth() * position); float rotation = 180f * position; page.setAlpha(rotation > 90f || rotation -0.5f && position page.setVisibility(View.INVISIBLE); } } private float getCameraDistance() { DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics(); float density = displayMetrics.density; int widthPixels = displayMetrics.widthPixels; int heightPixels = displayMetrics.heightPixels; return 1.5f * Math.max(widthPixels, heightPixels) * density; } }

9、竖直翻转效果(上下翻转) 上下翻转

即以竖直中心线为旋转中心,绕 X 轴旋转。代码如下所示,同样要注意镜头距离:

/** * 竖直翻转效果 */ public class FlipVerticalTransformer implements ViewPager.PageTransformer { @Override public void transformPage(@NonNull View page, float position) { page.setCameraDistance(getCameraDistance()); page.setTranslationX(-page.getWidth() * position); float rotation = 180f * position; page.setAlpha(rotation > 90f || rotation -0.5f && position page.setVisibility(View.INVISIBLE); } } private float getCameraDistance() { DisplayMetrics displayMetrics = VpsApplication.getAppContext().getResources().getDisplayMetrics(); float density = displayMetrics.density; int widthPixels = displayMetrics.widthPixels; int heightPixels = displayMetrics.heightPixels; return 1.5f * Math.max(widthPixels, heightPixels) * density; } }

10、浮出效果 浮出效果

让所有右边页面都移动到 正中位置,从右向左滑动切换页面时,左边从右向左滑出,右边页面放大淡入。

/** * 浮出效果 */ public class RiseInTransformer implements ViewPager.PageTransformer { private static final float DEF_MIN_SCALE = 0.72f; private float mMinScale = DEF_MIN_SCALE; private static final float DEF_MIN_ALPHA = 0.5f; public RiseInTransformer() { } public RiseInTransformer(float minScale) { this.mMinScale = minScale; } public float getMinScale() { return mMinScale; } public void setMinScale(float minScale) { this.mMinScale = minScale; } @Override public void transformPage(@NonNull View page, float position) { if (position page.setTranslationX(-position * page.getWidth()); page.setScaleX(1f - (1f - mMinScale) * position); page.setScaleY(1f - (1f - mMinScale) * position); page.setAlpha(1f - (1f - DEF_MIN_ALPHA) * position); } else { page.setTranslationX(-position * page.getWidth()); page.setScaleX(mMinScale); page.setScaleY(mMinScale); page.setAlpha(DEF_MIN_ALPHA); } } }

调用时需要反转绘制顺序,即 reverseDrawingOrder = true,使左边页面先绘制,右边页面后绘制,否则效果无法实现。

int reverseDrawingOrder = true; mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);

11、下潜效果 下潜效果

让所有左边页面都移动到 正中位置,切换页面时,左边页面缩小淡出,右面页面从右向左滑入正中。

/** * 下潜效果 */ public class DiveOutTransformer implements ViewPager.PageTransformer { private static final float DEF_MIN_SCALE = 0.72f; private float mMinScale = DEF_MIN_SCALE; private static final float DEF_MIN_ALPHA = 0.5f; public DiveOutTransformer() { } public DiveOutTransformer(float minScale) { this.mMinScale = minScale; } public float getMinScale() { return mMinScale; } public void setMinScale(float minScale) { this.mMinScale = minScale; } @Override public void transformPage(@NonNull View page, float position) { if (position page.setTranslationX(-position * page.getWidth()); page.setScaleX(1f + (1f - mMinScale) * position); page.setScaleY(1f + (1f - mMinScale) * position); page.setAlpha(1f + (1f - DEF_MIN_ALPHA) * position); } else { page.setTranslationX(0f); } } }

调用时不需要反转绘制顺序,即 reverseDrawingOrder = false,使右边页面先绘制,左边页面后绘制,否则效果无法实现。

int reverseDrawingOrder = false; mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer);

12、堆叠效果 堆叠效果

所有右边页面移动到正中位置,即 0 位置,滑动时,把最上面页面滑掉,代码如下所示:

/** * 堆叠效果 */ public class StackTransformer implements ViewPager.PageTransformer { @Override public void transformPage(@NonNull View page, float position) { page.setTranslationX(position if (position //[-1, 1] if (position //[0, 1] page.setScaleX(1f - (1f - mMinScale) * position); page.setScaleY(1f - (1f - mMinScale) * position); } } else {//(1, +Infinity] page.setScaleX(mMinScale); page.setScaleY(mMinScale); } } }

并行覆盖效果 并行覆盖效果

通过调用 View 的 setScrollX() 方法,使页面内容随着 position 移动。

public class ParallaxTransformer implements ViewPager.PageTransformer { @Override public void transformPage(@NonNull View page, float position) { int width = page.getWidth(); if (position if (position page.setScrollX((int) (width * 0.75f * position)); } } else { page.setScrollX(0); } } }

调用时需要反转绘制顺序,即 reverseDrawingOrder = true,使左边页面先绘制,右边页面后绘制,否则效果无法实现。

int reverseDrawingOrder = true; mVpImgs.setPageTransformer(reverseDrawingOrder , mPageTransformer); 项目地址

https://github.com/wangzhengyangNo1/ViewPagerSerialDemo

4. 参考

【1】巧用ViewPager 打造不一样的广告轮播切换效果 【2】ViewPager 超详解:玩出十八般花样 【3】关于ViewPager.PageTransformer的一些理解 【4】一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有