转自: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动起来,实现无限轮播效果。