ViewPager的PageTransformer 实现各种Page变换动画效果分析
来源:互联网 发布:数据库建库 编辑:程序博客网 时间:2024/06/14 09:53
一,PageTransformer 的简单介绍
从Android 3.0开始,ViewPager提供了PageTransformer接口来帮助应用方便实现各种切换效果,该接口是在ViewPager滑动的时候被调用的,下面是其定义:
/** * A PageTransformer is invoked whenever a visible/attached page is scrolled. * This offers an opportunity for the application to apply a custom transformation * to the page views using animation properties. * * <p>As property animation is only supported as of Android 3.0 and forward, * setting a PageTransformer on a ViewPager on earlier platform versions will * be ignored.</p> */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. */ public void transformPage(View page, float position);}
从上面可以看出ViewPager实现各种Page页面变换的动画效果只要实现transformPage这一个方法即可,其中:
(1)page
用来表示当前被滑动的页面所对应的view,通过实际的使用会发现,滑动的时候其返回的page并不都是同一个对象,因为滑动不仅导致当前界面慢慢滑出屏幕,同时导致相关的新界面慢慢滑入屏幕,下面是通过源码查看其被调用的地方:
protected void onPageScrolled(int position, float offset, int offsetPixels) { ... if (mPageTransformer != null) { final int scrollX = getScrollX(); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.isDecor) continue; final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); mPageTransformer.transformPage(child, transformPos); } } ...}
可以看出,每次滑动时,都会依次取ViewPager中每个child然后调用transformPage方法,验证了上面我们说明的每次滑动时返回的page是可能不同的。
(2)position
给定界面的位置相对于屏幕中心的偏移量。在用户滑动界面的时候,是动态变化的。假设ViewPager中有A,B,C页面,当前停留在B界面,则B界面此时的position为0,A界面的position为-1,C界面的position为1,而后向左滑动界面(C -> B),此过程中A的position在区间(-Infinity,-1)变化,B的position在区间[-1,0)变化,C的position在区间[0,1)变化,并且会发现B的position跟C的position绝对值之和为1,而正负则表示了滑入和滑出状态。理解清楚了position的变化过程对后面如何利用PageTransformer实现各种变化是很有用的。
当应用实现好了PageTransformer接口后,就可以通过ViewPager提供的setPageTransformer()设置进去。
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer)
reverseDrawingOrder用来指定是否要改变page的绘制顺序,在getChildDrawingOrder()时会用到,true则表示从最后一个开始绘制。
通过对position的介绍可知,我们在实现PageTransformer时主要还是关注[-1,1] 区间的值。
首先拿最简单的AlphaPageTransformer变换来说,其实现如下:
public class AlphaPageTransformer implements ViewPager.PageTransformer { private float mMinAlpha = 0.5f; public void transformPage(View view, float position) { if (position < -1) { view.setAlpha(mMinAlpha); } else if (position <= 0) { float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position); view.setAlpha(factor); } else if(position <= 1){ float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position); view.setAlpha(factor); } else { view.setAlpha(mMinAlpha); } }}
可以总结出一套通用简单的规律:
public class DepthPageTransformer implements ViewPager.PageTransformer { public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { //具体实现,此时page在界面的左边并且已经不显示在当前界面 } else if (position <= 0) { //具体实现,此时page正从中间往左侧移动 } else if (position <= 1) { //具体实现,此时page正从右侧往中间移动 } else { //具体实现,此时page在界面的右边并且已经不显示在当前界面 } }}
三,如何实现视差滚动效果
视差滚动效果也是最近几年在手机上比较流行,一般应用场景是首次启动应用时的导航界面,根据上面的规律,结合自己的效果实现动画就可以了。只需在PageTransformer中先找到相关的view,然后根据position设置不同的水平平移距离即可,大致的伪代码如下所示:
public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 1) { // [-1,1] mBlur.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth)); mBlurLabel.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth)); mDim.setTranslationX((float) (-(1 - position) * pageWidth)); mDimLabel.setTranslationX((float) (-(1 - position) * pageWidth)); mCheck.setTranslationX((float) (-(1 - position) * 1.5 * pageWidth)); mDoneButton.setTranslationX((float) (-(1 - position) * 1.7 * pageWidth)); // The 0.5, 1.5, 1.7 values you see here are what makes the view move in a different speed. // The bigger the number, the faster the view will translate. // The result float is preceded by a minus because the views travel in the opposite direction of the movement. mFirstColor.setTranslationX((position) * (pageWidth / 4)); mSecondColor.setTranslationX((position) * (pageWidth / 1)); mTint.setTranslationX((position) * (pageWidth / 2)); mDesaturate.setTranslationX((position) * (pageWidth / 1)); // This is another way to do it } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); }}
四,与OnPageChangeListener的不同
OnPageChangeListener是很早就在ViewPager上提供的接口,其主要提供了在Page滑动时的一些回调,方便应用进行相关逻辑处理。
/** * Callback interface for responding to changing state of the selected page. */ public interface OnPageChangeListener { /** * This method will be invoked when the current page is scrolled, either as part * of a programmatically initiated smooth scroll or a user initiated touch scroll. * * @param position Position index of the first page currently being displayed. * Page position+1 will be visible if positionOffset is nonzero. * @param positionOffset Value from [0, 1) indicating the offset from the page at position. * @param positionOffsetPixels Value in pixels indicating the offset from position. */ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); /** * This method will be invoked when a new page becomes selected. Animation is not * necessarily complete. * * @param position Position index of the new selected page. */ public void onPageSelected(int position); /** * Called when the scroll state changes. Useful for discovering when the user * begins dragging, when the pager is automatically settling to the current page, * or when it is fully stopped/idle. * * @param state The new scroll state. * @see ViewPager#SCROLL_STATE_IDLE * @see ViewPager#SCROLL_STATE_DRAGGING * @see ViewPager#SCROLL_STATE_SETTLING */ public void onPageScrollStateChanged(int state); }
里面的onPageScrolled()方法也会在page滚动时会被实时调用,但是里面的position只是当前正在滚动页所在的position。按照上节动画的实现过程,一般来说,需要先找当前页和相邻页,然后根据偏移量对其添加动画,而onPageScrolled并不能提供所有相关页的信息,仅仅只是当前页的position,如果需要知道相邻页,就需要额外采取一些手段,更加详细的介绍可以参考http://blog.csdn.net/lmj623565791/article/details/38026503 里面的说明。当然如果非要通过OnPageChangeListener来实现以上的动画效果,也是可以的,这方面最出名的开源项目要数JazzyViewPager(https://github.com/jfeinstein10/JazzyViewPager) ,作者会先在ViewPager的Adapter中维护一个position与page对应关系的HashMap,然后在onPageScrolled()方法中就可以根据这个HashMap很方便的找到当前页以及相邻的页面,从而进行相关动画的设置。
正是因为通过onPageScrolled()来实现动画比较困难,所以后来ViewPager提供了PageTransformer ,更加方便应用来实现各种动画效果
相关参考文档:
http://blog.csdn.net/lmj623565791/article/details/38026503
http://blog.csdn.net/lmj623565791/article/details/51339751
http://www.lightskystreet.com/2014/12/15/viewpager-anim/
http://ryanhoo.github.io/blog/2014/07/16/step-by-step-implement-parallax-animation-for-splash-screen-of-zhihu/
各种炫酷的page变换效果
https://github.com/hongyangAndroid/MagicViewPager
https://github.com/daimajia/AndroidImageSlider
https://github.com/jfeinstein10/JazzyViewPager
各种视差滚动效果
https://github.com/Cleveroad/slidingtutorial-android
https://github.com/stephentuso/welcome-android
https://github.com/MoshDev/BackgroundViewPager
https://github.com/andraskindler/parallaxviewpager
- ViewPager的PageTransformer 实现各种Page变换动画效果分析
- Android ViewPager的切换动画效果PageTransformer
- PageTransformer实现个性的ViewPager切换动画
- 利用PageTransformer实现viewpager的视差效果变换和反转特效
- ViewPager使用PageTransformer的各种切换的效果
- Android 实现个性的ViewPager切换动画 实战PageTransformer
- Android 实现个性的ViewPager切换动画 实战PageTransformer
- 详解ViewPager无限循环及缩放动画PageTransformer的实现
- 自定义ViewPager.PageTransformer实现幻灯片效果
- ViewPager+Fragment+PageTransformer实现3D、视差等多种动画效果(雷惊风)
- ViewPager切换动画PageTransformer的使用
- ViewPager切换动画PageTransformer的使用
- Android viewpager 动画 PageTransformer
- 用PageTransformer打造更好的动画效果
- Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- 【Android】实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- 第25周-windows程序设计(基础篇)-第2章-Windows函数的呼叫及Windows的字符串函数
- linux fs
- 算法15_笔试_数字逻辑推理题1
- 2016 UESTC Training for Data Structures(2)
- Tomcat 导入eclipse
- ViewPager的PageTransformer 实现各种Page变换动画效果分析
- HDU 5898 odd-even number 2016年沈阳网络赛 (数位dp)
- JS-如何使用DOM操纵样式表
- 字典序问题
- 比特同步和帧同步的区别
- 【POJ3393】Lucky and Good Months by Gregorian Calendar
- hdu 5878 I Count Two Three 丑数 二分
- EL表达式
- tp 学习基础