本文没有提供酷炫的动画实现,而是分析理解如何使用自定义PageTransformer完成要想的效果。
从3.0开始,ViewPager开始支持自定义切换动画,官方提供的接口为PageTransformer,因此只要实现该接口即可,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. */ public void transformPage(View view, float position)transformPage()方法的关键在于position的理解,从doc注释来看,当前选中的item的position永远是0(这与ViewPager的OnPageChangeListener回调方法中的position不同),被选中item的前一个为-1,被选中item的后一个为1。** 其实这里文档的描述并不是完全正确的,前后item position为-1和1的前提是你没有给ViewPager设置pageMargin(通过调用viewPager.setPageMargin(int)方法设置)**。如果你设置了pageMargin,前后item的position需要分别加上(或减去,前减后加)一个偏移量(偏移量的计算方式为pageMargin / pageWidth)。 在用户滑动界面的时候,position是动态变化的,下面以左滑为例:
选中item position:0->-1 - offset (pageMargin / pageWidth)前一个item position:-1 - offset (pageMargin / pageWidth) -> -2 - offset (pageMargin / pageWidth),再往前就以此类推后一个item position:1 + offset (pageMargin / pageWidth) -> 0,再往后就以此类推因此我们可以将position的值应用于setAlpha(), setTranslationX(), 或者 setScaleY()等等方法,从而实现自定义的动画效果。
先看下布局,只有一个RelativeLayout,内部放置了一个ViewPager。
<RelativeLayout android:id="@+id/viewpager_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:clipChildren="false"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="200dp" android:layout_height="280dp" android:clipChildren="false" android:layout_centerInParent="true"> </android.support.v4.view.ViewPager> </RelativeLayout>为了ViewPager可以展示多个Item,这里分别设置其以及其父布局的clipChildren属性为false。
ViewPager滑动还有一个小技巧,我们都知道默认情况下ViewPager本身滑动才可以切换页面,所以就算屏幕上显示了多个item,当你滑动未被选中的item时,ViewPager也是无法切换页面的。如果想扩大滑动区域可以给ViewPager的父布局设置触摸监听,并将触摸事件交给ViewPager处理,这样即使滑动触摸位置为未选中item,ViewPager仍然可以相应滑动了。代码如下:
relativeLayout = (RelativeLayout) view.findViewById(R.id.viewpager_container); relativeLayout.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return viewPager.onTouchEvent(event); } });