前言
在Android中,ViewPager可以用来做页面切换,同时也可以实现基本的轮播效果,之前也对轮播做了个封装 ViewPager封装轮播效果+指示器 实现一行代码展示轮播图,但我们经常可以看到一些App的轮播效果会多样化,有些的效果会是左右两屏也各显示一部分,让用户明显感知到左右还有东西可以切换,另外有的还会加上一些切换动画,比如正中间是放大,左右两屏是稍微缩小,每次切换时,滑到中间时总会有放大效果。如下:
ViewPager如何实现一屏多图显示?
ViewPager提供了一个setPageMargin
方法,允许我们设置ViewPager的Item之间的间隔:
ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
viewPager.setPageMargin(64);
设置之后会是如下效果:
可以看到两边都有了边距,但是注意:这个边距是在中间图片的范围之外的,也就是说,假如我们的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添加切换动画?
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());
这样我们的切换放大效果就出来了:
更多动画效果
上面以放大效果做个例子,所以这也体现出Google设计的精妙之处,把动画效果的具体实现与ViewPager解耦开来,并且根据position
和view
两个参数联动,然后结合View的属性api比如setScale和setRotate、setAlpha等等,可以定义出各种各样的切换动画,比如下面这些效果:
将它们封装成了一个BannerView,集合了十几种切换特效,源码和demo均已上传到 GitHub-YBannerView
欢迎关注 Android小Y 的简书,更多Android精选自定义View
Android 玩转PathMeasure之自定义支付结果动画
Android 自定义弧形旋转菜单栏——卫星菜单
Android 自定义带入场动画的弧形百分比进度条
GitHub:GitHub-ZJYWidget
CSDN博客:IT_ZJYANG
简 书:Android小Y
在Github上建了一个集合炫酷自定义View的项目,里面有很多实用的自定义View源码及demo,会长期维护,欢迎Star~ 如有不足之处或建议还望指正,相互学习,相互进步,如果觉得不错动动小手给个Star, 谢谢~