使用ViewPager实现卡片叠加效果(效果很是棒)

咱们来看一下效果图:git

https://img.mukewang.com/5c417e2700019d0c00400016.jpg

背景github

在开发项目时,须要对 App的某个资源模块进行界面重构,其中在资源展现部分中新的交互以卡片叠加的效果替代了原来的资源组织树门禁展现方式。在新的资源展现方式中,每个新的卡片都是在最上面的,其顺序以栈的形式存储在内存。卡片支持叠加效果,左右滑动切换到下一页或上一页,且卡片中的资源是以列表的形式展现,支持上下滑动,上拉刷新,下拉加载更多。目前网上存在的卡片布局第三方库,并不能知足咱们的项目需求,有的是没法达到叠加效果,有的会是卡片中不能有列表,不然会产生View滑动事件冲突,致使列表没法滑动,所以考虑使用已有的知识,本身实现这样的功能。ide

 

实现                              布局

在Android系统中,没有能直接能实现该效果的控件,能够实现左右滑动切换页面的控件首先想到ViewPager,但ViewPager并不能直接实现页面叠加效果,经过查阅资料,发现能够自定义ViewPager.PageTransformer接口去控制ViewPager中各个页面的偏移显示效果。ui

 

编码尝试:编码

一、建立基本界面结构:orm

首先咱们先建立一个Activity,配置好页面,就像如下效果。一个ViewPager,里面放View。还须要给ViewPager的setOffscreenPageLimit一个大一点的值,这样可使Viewpager预加载多个页面。blog

正常状况下,ViewPager里面的内容是水平排列的,以下图:接口

https://img4.mukewang.com/5c417b8d000128cf04420646.jpg

 

如今要作的第一步,就是将ViewPager里面全部的view都显示在同一个位置,那么就须要自定义PageTransformer去实现了。事件

自定义PageTransformer:

PageTransformer介绍,当ViewPager中页面滑动切换时,将会回调方法transformPage(View page, float position);该方法有两个参数,第一个view固然就是当前正在滑动的页面,第二个是一个float类型的值,不是咱们日常见到的position位置,而是当前滑动状态的表示,相对于当前position的position。它有三个临界值-1 0 1,0表明当前屏幕显示的view的position,1表明当前view的下一个view所在的position,-1表明当前view的前一个view所在的position

https://img3.mukewang.com/5c417bb50001f06810080514.jpg

当前view左滑、右滑时各个view positon的变化状况: 

 

https://img4.mukewang.com/5c417bc80001154711360128.jpg

 

既然ViewPager里面的View默认是水平排列的,那么只要将每一个view的x轴坐标更改成:view的宽度乘如下标的负数,这样就排列在一块儿了,为了方便起见,还给view增长了一个透明度。代码以下:

public void transformPage(View page, float position) {

        //设置透明度

        page.setAlpha(0.5f);

        //设置每一个View在中间,即设置相对原位置偏移量

        page.setTranslationX((-page.getWidth() * position)); 

}

具体效果以下:

https://img2.mukewang.com/5c417c4300015ab006301046.jpg

卡片都叠加在了一块儿,说明X方向水平偏移达到了预期效果,而后还须要实现卡片在Y方向垂直偏移,和卡片大小的缩放操做,就能够实现叠加效果了,定义了一个变量mOffset表示偏移量,赋值为40px。

@Override
public void transformPage(View page, float position) {

    if (position > 0){
        //移动X轴坐标,使得卡片在同一坐标
        page.setTranslationX(-position * page.getWidth());
        //缩放卡片并调整位置
        float scale = (page.getWidth() - mOffset * position) / page.getWidth();
        page.setScaleX(scale);
        page.setScaleY(scale);
        //移动Y轴坐标
        page.setTranslationY(position * mOffset);
    }

}

为啥这里只处理position>0的状况呢,由于数据源中最新的那个数据放在list中的第0个,因此

要滑动下一个,是用手指往右往左滑动的,那么咱们只要把position>0的那些view都设置

translationX坐标让他们叠到第一个view的下面就好了,而后就设置他们的translationY

 

那咱们怎么实现拿手势从左往右滑看历史呢,咱们就要把数据源中最新的那条数据放到list的最后一个,

而后进去后让viewpager定位到最后一页,而后咱们要处理position<0的那些view就好了

public class CardTransformer implements ViewPager.PageTransformer {

    private int mOffset = 40;

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void transformPage(View page, float position) {

        if (position <=0) {
            page.setTranslationX(-position * page.getWidth());
            //缩放卡片并调整位置
            float scale = (page.getWidth() + mOffset * position) / page.getWidth();
            page.setScaleX(scale);
            page.setScaleY(scale);
            //移动Y轴坐标
            page.setTranslationY(-position * mOffset);
            page.setTranslationZ(position);
        }

    }

}

这个translationZ是什么做用呢,实际上是设置view的层级,translationZ越大,说明他的层级越高

因此position = -1的view的层级就比position=0的view的层级低,那么position=0的view就会叠在

position=-1的view的上面,这样就实现了效果

项目的代码在https://github.com/nickgao1986/ViewPaperSwitch

若是喜欢这个效果,请帮忙点个赞,谢谢