转自:http://www.jianshu.com/p/653680cfe877# 目的:添加自己的理解和注释。 主要改动:展示多页的更深解释、动画效果的优化。 1 . ViewPager展示多页 要让ViewPager页面展示多页的内容,就要用到ViewGroup的一个强大的属性。这个属性虽然强大,但是也不常用,可能有些小伙伴不知道(之前我也没用过…),那就是clipChildren属性。这个属性有什么作用呢,我们看一下它的文档介绍:
/** * By default, children are clipped to their bounds before drawing. This * allows view groups to override this behavior for animations, etc. * * @param clipChildren true to clip children to their bounds, * false otherwise * @attr ref android.R.styleable#ViewGroup_clipChildren */clipChildren: 默认值为true, 子View 的大小只能在父View规定的范围之内,比如父View的高为50,子View的高为60 ,那么多处的部分就会被裁剪。如果我们设置这个值为false的话,那么多处的部分就不会被裁剪了。
clipChildren的意思:是否限制子View在其范围内,我们将其值设置为false后那么当子控件的高度高于父控件时也会完全显示,而不会被压缩,ViewPager是一组连续的图片,我们设置了false,其实父控件也不能控制ViewPager的大小了。
这里我们就可以利用这个属性来实现了这个效果了,我们设置ViewPager的父布局的clipChildren为false。然后设置ViewPager 左右一定的边距,那么左右就空出了一定的区域,利用clipChildren 属性,就能让前后页面的部分显示在当前页了。布局如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:clipChildren="false" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="200dp" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" /> </LinearLayout>这样就能实现ViewPager 展示前后页面的部分内容。 2 . 自定义ViewPager.PageTransformer动画 上面实现了ViewPager当前页面显示前后页的部分内容,但是从最开始魅族的Banner效果我们可以看出,滑动的时候是有 一个放大缩小的动画的。左右显示的部分有一定比例的缩小。这就要用到ViewPager.PageTransformer了。
ViewPager.PageTransformer 干什么的呢?ViewPager.PageTransformer 是用来做ViewPager切换动画的,它是一个接口,里面只有一个方法transformPage。
public interface PageTransformer { /** * Apply a property transformation to the given page. * * @param page Apply the transformation to this page * @param position Position of page relative to the current front-and-center * position of the pager. 0 is front and center. 1 is one full * page position to the right, and -1 is one page position to the left. */ void transformPage(View page, float position); }虽然只有一个方法,但是它很强大,它能反映出在ViewPager滑动过程中,各个View的位置变化。我们拿到了这些位置变化,就能在这个过程中对View做各种各样的动画了。
要自定义动画,我们就来需要知道positon这个值的变化区间。从官方给的ViewPager的两个示例我们知道,position的变换有三个区间,[-Infinity,-1),[-1,1],(1.Infinity)。 [-Infinity,-1):已经在屏幕之外,看不到了 (1.Infinity): 已经在屏幕之外,看不到了。 [-1,1]: 这个区间是我门操作View动画的重点区间。 我们来看一下官方对于position的解释:
官方的解释:The position parameter indicates where a given page is located relative to the center of the screen. It is a dynamic property that changes as the user scrolls through the pages. When a page fills the screen, its position value is 0. When a page is drawn just off the right side of the screen, its position value is 1. If the user scrolls halfway between pages one and two, page one has a position of -0.5 and page two has a position of 0.5.根据解释,也就是说当前停留的页面的位置为 0,右边屏幕之外绘制的这个页面位置为 1。那么,A 页面滑到 B 页面有 2 种情况:第一种:左边划出屏幕,那么 A:0 -> -1,B :1 -> 0。第二种:右边划出屏幕,A:0->1, B :-1-> 0
了解了这个方法的变化后,我们就来自定义我们的切换动画,这里很简单,我们只需要一个scale动画。代码如下:
public class CustomTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.9F; @Override public void transformPage(View page, float position) { Log.e("xsr", "position = " + position + ", page = " + page); if (position <= -1) { page.setScaleY(MIN_SCALE); } else if (position < 1 && position > -1) { // position会显示ViewPager里面的所有的位置。这些位置都是相对于中间(0)位置的。最中间是0,往右:1,2,3。。。往左:-1,-2,-3。。。相对位置越靠近中间(0),数值越小。相当于就是-1到0到1之间无穷的小数。所以我们直接取到这个位置的绝对值,然后乘以0.1f得到缩小的距离比例。然后再用1减去,得到最终的比例。 float scale = 1 - Math.abs(position) * 0.1f; Log.e("xsr", "scale = " + scale); page.setScaleY(scale); /*page.setScaleX(scale); if(position<0){ page.setTranslationX(width * (1 - scale) /2); }else{ page.setTranslationX(-width * (1 - scale) /2); }*/ } else { page.setScaleY(MIN_SCALE); } } }到此,我们仿魅族Banner的静态效果就实现了。接下来我们就要让Banner动起来,实现无限轮播效果。