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

前言

在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, 谢谢~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容