转载请注明出处:http://blog.csdn.net/allen315410/article/details/44200623
ViewPager作为Android最经常使用的的组件之中的一个,相信大家在项目中会频繁的使用到的,比如利用ViewPager制作引导页、轮播图,甚至做整个app的表现层的框架等等。
可是在Android 3.0(API 11)下面的ViewPager是比較死板的,不支持动画特效的。这也就让ViewPager在切换的时候达不到非常好的用户体验,下面就是Android3.0下面不加入动画的ViewPager的实现代码以及效果演示:
public class MainActivity extends Activity { private ViewPager mViewPager; private int[] imgRes = new int[] { R.drawable.guide_image1, R.drawable.guide_image2, R.drawable.guide_image3 }; private List<ImageView> imgList = new ArrayList<ImageView>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setAdapter(new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public int getCount() { return imgRes.length; } @Override public Object instantiateItem(ViewGroup container, int position) { ImageView mImageView = new ImageView(MainActivity.this); mImageView.setBackgroundResource(imgRes[position]); mImageView.setScaleType(ScaleType.CENTER_CROP); imgList.add(mImageView); container.addView(mImageView); return mImageView; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(imgList.get(position)); } }); } }上面是最简单的ViewPager使用的Demo,执行例如以下。看起来非常普通非常死板:
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer){...}当中第一个參数boolean类型设置true就好,第二个參数PageTransformer就是我们自己定义好的动画效果:
mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());当中ZoomOutPageTransformer的代码来自于google的training文档中,英文好的朋友能够直接进入文档查看,链接是
public class ZoomOutPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.85f; private static final float MIN_ALPHA = 0.5f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); int pageHeight = view.getHeight(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 1) { // [-1,1] // Modify the default slide transition to shrink the page as well float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position)); float vertMargin = pageHeight * (1 - scaleFactor) / 2; float horzMargin = pageWidth * (1 - scaleFactor) / 2; if (position < 0) { view.setTranslationX(horzMargin - vertMargin / 2); } else { view.setTranslationX(-horzMargin + vertMargin / 2); } // Scale the page down (between MIN_SCALE and 1) view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); // Fade the page relative to its size. view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA)); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }另外Google文档中还提供了另外一个动画的实现方式,我暂且把源代码附在以下:
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; 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 <= 0) { // [-1,0] // Use the default slide transition when moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } }两种方式的所实现的效果例如以下所看到的,一是ZoomOutPageTransformer。二是DepthPageTransformer
分析出了不能在Android3.0下面版本号中加入动画的原因后,我们就能够通过其他的方法来解决这个兼容性的问题了。
public class DepthPageTransformer implements ViewPager.PageTransformer { private static final float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // view.setAlpha(0); ViewHelper.setAlpha(view, 0); } else if (position <= 0) { // view.setAlpha(1); ViewHelper.setAlpha(view, 1); // view.setTranslationX(0); ViewHelper.setTranslationX(view, 0); // view.setScaleX(1); ViewHelper.setScaleX(view, 1); // view.setScaleY(1); ViewHelper.setScaleY(view, 1); } else if (position <= 1) { // view.setAlpha(1 - position); ViewHelper.setAlpha(view, 1 - position); // view.setTranslationX(pageWidth * -position); ViewHelper.setTranslationX(view, pageWidth * -position); float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); // view.setScaleX(scaleFactor); ViewHelper.setScaleX(view, scaleFactor); // view.setScaleY(scaleFactor); ViewHelper.setScaleY(view, scaleFactor); } else { // view.setAlpha(0); ViewHelper.setAlpha(view, 0); } } }为了好理解,我没有将Google提供的源代码删除,而是凝视掉了,方便大家进行比較阅读。然而即使这样使用了NineOldAndroids对我们的动画源代码进行了改造。当我们打开一个Android2.3的模拟器执行一下的时候发现,没有起到效果,也就是这个动画效果并没有执行,在模拟器上执行的ViewPager滑动的效果还是原始默认的左右来回切换的动画,这又是怎么回事呢?为止,我们须要打开ViewPager的源代码进行阅读一下了。既然是在mViewPager.setPageTransformer(true, new DepthPageTransformer());这句代码没有起到效果。那么我们就点进去查看一下setPageTransformer这种方法的源代码,源代码例如以下:
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer){ if (Build.VERSION.SDK_INT >= 11) { boolean hasTransformer = transformer != null; boolean needsPopulate = hasTransformer != (this.mPageTransformer != null); this.mPageTransformer = transformer; setChildrenDrawingOrderEnabledCompat(hasTransformer); if (hasTransformer) { this.mDrawingOrder = (reverseDrawingOrder ? 2 : 1); } else { this.mDrawingOrder = 0; } if (needsPopulate) populate(); } }好了,源代码一目了然。我们分析到在ViewPager中的setPageTransFormer这种方法中,首先推断了一下当前设备的Build.VERSION_SDK_INT>=11,也就是说当前设备是Android3.0以上系统的话。这种方法体运行没问题,可是若是3.0一下,那就抱歉。无法运行了。知道这个原因之后我们就须要解决问题了,我在这里改动了一下ViewPager的源代码。改动ViewPager的源代码之前,读者能够先去下载一份ViewPager的源代码。然后复制到project中,又一次命名一下,将里面的if推断语句给删除了。
下面就是我改动后的部分源代码,命名为ViewPagerCompat:
public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) { // if (Build.VERSION.SDK_INT >= 11) { final boolean hasTransformer = transformer != null; final boolean needsPopulate = hasTransformer != (mPageTransformer != null); mPageTransformer = transformer; setChildrenDrawingOrderEnabledCompat(hasTransformer); if (hasTransformer) { mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; } else { mDrawingOrder = DRAW_ORDER_DEFAULT; } if (needsPopulate) populate(); // } }好。源代码改动完成,将您的源代码中的ViewPager替换成这个改动后的源代码ViewPagerCompat,那么ViewPager切换动画的效果就出现了。
public void transformPage(View view, float position) { ... Log.i("TAG", "view = " + view + ",position = " + position); ... }如上所看到的,我先在这种方法中打印出方法中的參数view对象和position的值,然后我们来看一下LOG的输出:
/** * ViewPager自己定义旋转动画 * * @author Vincent * */ public class RotateDownTransformer implements PageTransformer { // 旋转的最大角度为20度 private static final float MAX_ROTATE = 20.0f; // 旋转过程中的角度 private float currentRotate; @Override public void transformPage(View view, float position) { int pageWidth = view.getWidth(); Log.i("TAG", "view = " + view + ",position = " + position); if (position < -1) { ViewHelper.setRotation(view, 0); } else if (position <= 0) { // position范围[-1.0,0.0],此时A页动画移出屏幕 currentRotate = position * MAX_ROTATE; // 设置当前页的旋转中心点,横坐标是屏幕宽度的1/2,纵坐标为屏幕的高度 ViewHelper.setPivotX(view, pageWidth / 2); ViewHelper.setPivotY(view, view.getHeight()); ViewHelper.setRotation(view, currentRotate); } else if (position <= 1) { // position范围(0.0,1.0],此时B页动画移到屏幕 currentRotate = position * MAX_ROTATE; // 设置当前页的旋转中心点,横坐标是屏幕宽度的1/2,纵坐标为屏幕的高度 ViewHelper.setPivotX(view, pageWidth / 2); ViewHelper.setPivotY(view, view.getHeight()); ViewHelper.setRotation(view, currentRotate); } else { ViewHelper.setRotation(view, 0); } } }