Android ViewPager多屏显示、切换动画,让你的轮播炫起来

8字数 1366阅读 1996

前言

在Android中,ViewPager可以用来做页面切换,同时也可以实现基本的轮播效果,之前也对轮播做了个封装 ViewPager封装轮播效果+指示器 实现一行代码展示轮播图,但我们经常可以看到一些App的轮播效果会多样化,有些的效果会是左右两屏也各显示一部分,让用户明显感知到左右还有东西可以切换,另外有的还会加上一些切换动画,比如正中间是放大,左右两屏是稍微缩小,每次切换时,滑到中间时总会有放大效果。如下:

示意图

 

ViewPager如何实现一屏多图显示?

ViewPager提供了一个setPageMargin方法,允许我们设置ViewPager的Item之间的间隔:

ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
viewPager.setPageMargin(64);

设置之后会是如下效果:


setPageMargin.gif

可以看到两边都有了边距,但是注意:这个边距是在中间图片的范围之外的,也就是说,假如我们的Item的宽度是填充屏幕两边的话,那这个边距只有在拖动时才能看得到,否则当ViewPager不滑动时,这块区域是在屏幕外的。

但这不是我们想要的效果,如何让这个边距显示在屏幕内呢?可以为ViewPager设置一个margin值,并且这个margin值要比setPageMargin设置的值还大,并且为ViewPager设置setClipChildren为false,让它不裁剪Item,由于setPageMargin比margin小,所以两边就都能露出一点空间显示出来。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"
    >

    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:layout_marginLeft="64dp"
        android:layout_marginRight="64dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="16dp">

    </android.support.v4.view.ViewPager>
    
</FrameLayout>

记得ViewPager的父布局和它本身都要设置setClipChildren为false,以允许子View在父View的范围外显示。并且viewPager的setOffscreenPageLimit要设置为3以上,否则两边的Item都没有预加载,没法显示。

viewPager.setOffscreenPageLimit(3);
viewPager.setPageMargin(32);
viewPager.setClipChildren(false);

效果如下:


ViewPager多屏显示

 

如何为ViewPager添加切换动画?

Android在3.0之后提供了ViewPager设置切换动画的接口——PageTransformer,只要实现这个接口,重写它的transformPage(View view, float position)方法,然后通过ViewPager的setPageTransformer设置给ViewPager,即可自定义动画效果。

public class CustomPageTransformer implements ViewPager.PageTransformer {
    @Override
    public void transformPage(View view, float position) {
        //这里自定义动画
    }
}

transformPage方法有两个参数,第一个参数是一个View,第二个参数是一个float类型的值,它不是代表ViewPager的Item的position位置,而是代表当前滑动状态。它有三个临界值-1 0 1。当ViewPager右滑时,两个参数代表的意义如下:

当position返回值为0时,代表这个View刚好移动到正中间。
当position返回值为0~1时,代表这个View准备从左向右移动离开屏幕,移动停止时,position刚好等于1
当position返回值为-1~0时,代表这个View准备从左向右进入屏幕,移动停止时,position刚好等于0

所以我们可以通过这个方法控制每次切换时的动画过程,比如说一个切换时放大的效果,可以在transformPage中判断position的值。如果是-1到0的话,就说明当前这个View是准备进入屏幕,那我们应该给它一个逐渐放大的动画,如果是0到1的话,说明当前这个View是准备离开屏幕,就该给它设置一个逐渐缩小的动画,当position等于0时,要处于最大的状态:

public class ScalePageTransformer implements ViewPager.PageTransformer {
    //最小状态时,Size缩小为90%
    private static final float MIN_SCALE = 0.9F;
![banner切换动画效果图.gif](https://upload-images.jianshu.io/upload_images/16311248-ab59737f9fb15304.gif?imageMogr2/auto-orient/strip)

    @Override
    public void transformPage(View view, float position) {
        float scale = Math.max(MIN_SCALE,1 - Math.abs(position));
        if (position < -1.0f) {
            view.setScaleY(MIN_SCALE);
        } else if (position <= 0.0f) {
            view.setScaleY(scale);
        } else if (position <= 1.0f) {
            view.setScaleY(scale);
        } else {
            view.setScaleY(MIN_SCALE);
        }
    }
}

当position处于(-1,1)这个范围之外时,说明它在当前屏幕中是完全不可见的,肯定应该处于最小的状态。当position处于(-1,0)或者(0,1)之间时,1-Math.abs(position)的变化是在0和1之间,当它比0.9还小时,就取0.9,如果比0.9大,就用它来作为当前放大的比例(也就是说控制放大比例在90%到100%之间),当position刚好等于0时,View刚好滑到最中间,scale就应该为1,也就是最大的状态。

然后将我们的PageTransformer设置给ViewPager:

viewPager.setPageTransformer(true, new ScalePageTransformer());

 
这样我们的切换放大效果就出来了:


ViewPager切换放大效果.gif

 

更多动画效果

上面以放大效果做个例子,所以这也体现出Google设计的精妙之处,把动画效果的具体实现与ViewPager解耦开来,并且根据positionview两个参数联动,然后结合View的属性api比如setScale和setRotate、setAlpha等等,可以定义出各种各样的切换动画,比如下面这些效果:



将它们封装成了一个BannerView,集合了十几种切换特效,源码和demo均已上传到 GitHub-YBannerView

 

欢迎关注 Android小Y 的简书,更多Android精选自定义View

Android 玩转PathMeasure之自定义支付结果动画
Android 自定义弧形旋转菜单栏——卫星菜单
Android 自定义带入场动画的弧形百分比进度条

GitHubGitHub-ZJYWidget
CSDN博客IT_ZJYANG
简 书Android小Y
在Github上建了一个集合炫酷自定义View的项目,里面有很多实用的自定义View源码及demo,会长期维护,欢迎Star~ 如有不足之处或建议还望指正,相互学习,相互进步,如果觉得不错动动小手给个Star, 谢谢~

关注Android 技术小栈,更多精彩原创

推荐阅读更多精彩内容