手记

使用ViewPager实现卡片叠加效果

我们来看一下效果图:

背景

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


实现                              

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


编码尝试:

1、创建基本界面结构:

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

正常情况下,ViewPager里面的内容是水平排列的,如下图:


现在要做的第一步,就是将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

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



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

public void transformPage(View page, float position) {

        //设置透明度

        page.setAlpha(0.5f);

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

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

}

具体效果如下:

卡片都叠加在了一起,说明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

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

参考:http://www.cocoachina.com/cms/wap.php?action=article&id=21603

1人推荐
随时随地看视频
慕课网APP