1、概述

之前写过一篇博文:Android 自定义 ViewPager 打造千变万化的图片切换效果。有兄弟提出,ViewPager自带了一个setPageTransformer用于设置切换动画~

本篇博文,将:

1、介绍如何使用setPageTransformer设置切换动画;

2、自定义PageTransformer实现个性的切换动画;

3、该方法在SDK11以下的版本不起作用,我们会对其做一定修改,让其向下兼容。

官方示例地址:http://developer.android.com/training/animation/screen-slide.html 有兴趣的可以去看看~~


好了,下面开始编写代码~~

2、setPageTransformer的使用

首先我们迅速的实现一个传统的ViewPager效果~

1、布局文件

[html]  view plain copy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <android.support.v4.view.ViewPager  
  7.         android:id="@+id/id_viewpager"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent" />  
  10.   
  11. RelativeLayout>  

2、MainActivity

[java]  view plain copy
  1. package com.zhy.demo_zhy_08_viewpageranim;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.os.Bundle;  
  8. import android.support.v4.view.PagerAdapter;  
  9. import android.support.v4.view.ViewPager;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.view.Window;  
  13. import android.widget.ImageView;  
  14. import android.widget.ImageView.ScaleType;  
  15.   
  16. public class MainActivity extends Activity  
  17. {  
  18.     private ViewPager mViewPager;  
  19.     private int[] mImgIds = new int[] { R.drawable.guide_image1,  
  20.             R.drawable.guide_image2, R.drawable.guide_image3 };  
  21.     private List mImageViews = new ArrayList();  
  22.   
  23.     @Override  
  24.     protected void onCreate(Bundle savedInstanceState)  
  25.     {  
  26.         super.onCreate(savedInstanceState);  
  27.   
  28.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
  29.         setContentView(R.layout.activity_main);  
  30.   
  31.         initData();  
  32.   
  33.         mViewPager = (ViewPager) findViewById(R.id.id_viewpager);  
  34.   
  35.         mViewPager.setAdapter(new PagerAdapter()  
  36.         {  
  37.             @Override  
  38.             public Object instantiateItem(ViewGroup container, int position)  
  39.             {  
  40.   
  41.                 container.addView(mImageViews.get(position));  
  42.                 return mImageViews.get(position);  
  43.             }  
  44.   
  45.             @Override  
  46.             public void destroyItem(ViewGroup container, int position,  
  47.                     Object object)  
  48.             {  
  49.   
  50.                 container.removeView(mImageViews.get(position));  
  51.             }  
  52.   
  53.             @Override  
  54.             public boolean isViewFromObject(View view, Object object)  
  55.             {  
  56.                 return view == object;  
  57.             }  
  58.   
  59.             @Override  
  60.             public int getCount()  
  61.             {  
  62.                 return mImgIds.length;  
  63.             }  
  64.         });  
  65.   
  66.     }  
  67.   
  68.     private void initData()  
  69.     {  
  70.         for (int imgId : mImgIds)  
  71.         {  
  72.             ImageView imageView = new ImageView(getApplicationContext());  
  73.             imageView.setScaleType(ScaleType.CENTER_CROP);  
  74.             imageView.setImageResource(imgId);  
  75.             mImageViews.add(imageView);  
  76.         }  
  77.     }  
  78.   
  79. }  

好了,这样一个传统ViewPager就实现了~~大家对上面代码应该不会有任何陌生的感觉~运行效果也不用贴图了,大家肯定知道~~

3、PageTransformer

ViewPager有个方法叫做:

setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) 用于设置ViewPager切换时的动画效果,并且google官方还给出了两个示例。

只需要在上述代码中调用setPageTransformer即可添加切换动画效果~~下面演示google的两个PageTransformer的代码,以及运行效果。

1、DepthPageTransformer

[java]  view plain copy
  1. public class DepthPageTransformer implements ViewPager.PageTransformer {  
  2.     private static final float MIN_SCALE = 0.75f;  
  3.   
  4.     public void transformPage(View view, float position) {  
  5.         int pageWidth = view.getWidth();  
  6.   
  7.         if (position < -1) { // [-Infinity,-1)  
  8.             // This page is way off-screen to the left.  
  9.             view.setAlpha(0);  
  10.   
  11.         } else if (position <= 0) { // [-1,0]  
  12.             // Use the default slide transition when moving to the left page  
  13.             view.setAlpha(1);  
  14.             view.setTranslationX(0);  
  15.             view.setScaleX(1);  
  16.             view.setScaleY(1);  
  17.   
  18.         } else if (position <= 1) { // (0,1]  
  19.             // Fade the page out.  
  20.             view.setAlpha(1 - position);  
  21.   
  22.             // Counteract the default slide transition  
  23.             view.setTranslationX(pageWidth * -position);  
  24.   
  25.             // Scale the page down (between MIN_SCALE and 1)  
  26.             float scaleFactor = MIN_SCALE  
  27.                     + (1 - MIN_SCALE) * (1 - Math.abs(position));  
  28.             view.setScaleX(scaleFactor);  
  29.             view.setScaleY(scaleFactor);  
  30.   
  31.         } else { // (1,+Infinity]  
  32.             // This page is way off-screen to the right.  
  33.             view.setAlpha(0);  
  34.         }  
  35.     }  
  36. }  

调用代码:

[java]  view plain copy
  1. mViewPager.setPageTransformer(truenew DepthPageTransformer());  

效果:


2、ZoomOutPageTransformer

[java]  view plain copy
  1. package com.zhy.view;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.support.v4.view.ViewPager;  
  5. import android.util.Log;  
  6. import android.view.View;  
  7.   
  8. public class ZoomOutPageTransformer implements ViewPager.PageTransformer  
  9. {  
  10.     private static final float MIN_SCALE = 0.85f;  
  11.     private static final float MIN_ALPHA = 0.5f;  
  12.   
  13.     @SuppressLint("NewApi")  
  14.     public void transformPage(View view, float position)  
  15.     {  
  16.         int pageWidth = view.getWidth();  
  17.         int pageHeight = view.getHeight();  
  18.   
  19.         Log.e("TAG", view + " , " + position + "");  
  20.   
  21.         if (position < -1)  
  22.         { // [-Infinity,-1)  
  23.             // This page is way off-screen to the left.  
  24.             view.setAlpha(0);  
  25.   
  26.         } else if (position <= 1//a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0  
  27.         { // [-1,1]  
  28.             // Modify the default slide transition to shrink the page as well  
  29.             float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));  
  30.             float vertMargin = pageHeight * (1 - scaleFactor) / 2;  
  31.             float horzMargin = pageWidth * (1 - scaleFactor) / 2;  
  32.             if (position < 0)  
  33.             {  
  34.                 view.setTranslationX(horzMargin - vertMargin / 2);  
  35.             } else  
  36.             {  
  37.                 view.setTranslationX(-horzMargin + vertMargin / 2);  
  38.             }  
  39.   
  40.             // Scale the page down (between MIN_SCALE and 1)  
  41.             view.setScaleX(scaleFactor);  
  42.             view.setScaleY(scaleFactor);  
  43.   
  44.             // Fade the page relative to its size.  
  45.             view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)  
  46.                     / (1 - MIN_SCALE) * (1 - MIN_ALPHA));  
  47.   
  48.         } else  
  49.         { // (1,+Infinity]  
  50.             // This page is way off-screen to the right.  
  51.             view.setAlpha(0);  
  52.         }  
  53.     }  
  54. }  

调用代码:

[java]  view plain copy
  1. mViewPager.setPageTransformer(truenew ZoomOutPageTransformer());  

效果:



效果图都是google官网上的,我们的测试图会在兼容3.0以下贴出来,不然就重复了~~

为ViewPager添加切换就一行代码是不是很happy,可惜是不兼容3.0以下的版本的,该方法的注释上写到:

setting a PageTransformer prior to Android 3.0 (API 11) will have no effect 在3.0之前的版本设置此方法是没有效果的,那么下面我们就看如何让其兼容3.0以下版本。

3、版本的向下兼容

1、不兼容的原因

首先看下为什么不兼容,3.0以下呢?

看上面的两个示例代码,代码中View的动画使用的是属性动画,而属性动画是3.0才推出的,那么这么写肯定是不兼容3.0以下了~

那么我们首先引入nineoldandroids,让动画先能在3.0以下跑再说:

修改DepthPageTransformer

[java]  view plain copy
  1. package com.zhy.view;  
  2.   
  3. import com.nineoldandroids.view.ViewHelper;  
  4.   
  5. import android.annotation.SuppressLint;  
  6. import android.support.v4.view.ViewPager;  
  7. import android.view.View;  
  8.   
  9. public class DepthPageTransformer implements ViewPager.PageTransformer  
  10. {  
  11.     private static final float MIN_SCALE = 0.75f;  
  12.   
  13.     public void transformPage(View view, float position)  
  14.     {  
  15.         int pageWidth = view.getWidth();  
  16.   
  17.         if (position < -1)  
  18.         { // [-Infinity,-1)  
  19.             // This page is way off-screen to the left.  
  20.             // view.setAlpha(0);  
  21.             ViewHelper.setAlpha(view, 0);  
  22.         } else if (position <= 0)// a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0  
  23.         { // [-1,0]  
  24.             // Use the default slide transition when moving to the left page  
  25.             // view.setAlpha(1);  
  26.             ViewHelper.setAlpha(view, 1);  
  27.             // view.setTranslationX(0);  
  28.             ViewHelper.setTranslationX(view, 0);  
  29.             // view.setScaleX(1);  
  30.             ViewHelper.setScaleX(view, 1);  
  31.             // view.setScaleY(1);  
  32.             ViewHelper.setScaleY(view, 1);  
  33.   
  34.         } else if (position <= 1)  
  35.         { // (0,1]  
  36.             // Fade the page out.  
  37.             // view.setAlpha(1 - position);  
  38.             ViewHelper.setAlpha(view, 1 - position);  
  39.   
  40.             // Counteract the default slide transition  
  41.             // view.setTranslationX(pageWidth * -position);  
  42.             ViewHelper.setTranslationX(view, pageWidth * -position);  
  43.   
  44.             // Scale the page down (between MIN_SCALE and 1)  
  45.             float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - position);  
  46.             // view.setScaleX(scaleFactor);  
  47.             ViewHelper.setScaleX(view, scaleFactor);  
  48.             // view.setScaleY(1);  
  49.             ViewHelper.setScaleY(view, scaleFactor);  
  50.   
  51.         } else  
  52.         { // (1,+Infinity]  
  53.             // This page is way off-screen to the right.  
  54.             // view.setAlpha(0);  
  55.             ViewHelper.setAlpha(view, 1);  
  56.         }  
  57.     }  
  58. }  

很简单,把所有属性动画换成ViewHelper去设置就好了。现在我们去3.0以下的机子上去运行,发现还是没有效果~~~

为什么呢?

我们再去看看setPageTransformer的源码:

[java]  view plain copy
  1. public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {  
  2.        if (Build.VERSION.SDK_INT >= 11) {  
  3.            final boolean hasTransformer = transformer != null;  
  4.            final boolean needsPopulate = hasTransformer != (mPageTransformer != null);  
  5.            mPageTransformer = transformer;  
  6.            setChildrenDrawingOrderEnabledCompat(hasTransformer);  
  7.            if (hasTransformer) {  
  8.                mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;  
  9.            } else {  
  10.                mDrawingOrder = DRAW_ORDER_DEFAULT;  
  11.            }  
  12.            if (needsPopulate) populate();  
  13.        }  
  14.    }  

终于发现原因了,原来在此方法内部判断了如果是11以上的版本才让动画生效~~

那么,没办法了,如果想兼容,必须修改ViewPager的源码了~~

2、完美向下兼容

我们将ViewPager的源码拷贝一份至我们的项目中,修改名称为ViewPagerCompat;然后注释掉SDK版本判断那一句

public class ViewPagerCompat extends ViewGroup {

[java]  view plain copy
  1. public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {  
  2. //        if (Build.VERSION.SDK_INT >= 11)   
  3.         {  
  4.             final boolean hasTransformer = transformer != null;  
  5.             final boolean needsPopulate = hasTransformer != (mPageTransformer != null);  
  6.             mPageTransformer = transformer;  
  7.             setChildrenDrawingOrderEnabledCompat(hasTransformer);  
  8.             if (hasTransformer) {  
  9.                 mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD;  
  10.             } else {  
  11.                 mDrawingOrder = DRAW_ORDER_DEFAULT;  
  12.             }  
  13.             if (needsPopulate) populate();  
  14.         }  
  15.     }  
...
}

注意,所有的PageTransformer使用ViewPager.PageTransformer

然后我们把项目中的ViewPager改为ViewPagerCompat;记得修改布局文件,以及MainActivity中的ViewPager为ViewPagerCompat

我们在2.3.3的模拟器上测试下效果:



可以看到,我们的切换动画完美的运行在2.3.3的机器上~~so happy ~~没有ViewPager源码的童鞋不要紧,我会在文末的源码下载中加入ViewPager源码,让你可以尽情去测试~~

当然了,仅仅是兼容当然不能满足我们的好奇心,难道我们做到了兼容,还只能使用Google给的示例动画么~~我们强大的创新呢~~下面带领大家分析setPageTransformer方法,然后设计一个个性的动画切换效果

4、自定义PageTransformer实现个性切换动画

[java]  view plain copy
  1. public interface PageTransformer {  
  2.        /** 
  3.         * Apply a property transformation to the given page. 
  4.         * 
  5.         * @param page Apply the transformation to this page 
  6.         * @param position Position of page relative to the current front-and-center 
  7.         *                 position of the pager. 0 is front and center. 1 is one full 
  8.         *                 page position to the right, and -1 is one page position to the left. 
  9.         */  
  10.        public void transformPage(View page, float position);  
  11.    }  

可以看到该接口只有一个方法,第一个是我们的view,第二个是position~~

当我们滑动时:会打印出当然ViewPager中存活的每个View以及它们的position的变化~~注意是每一个,所以建议别只log position,不然你会觉得莫名其妙的输出~~

position的可能性的值有,其实从官方示例的注释就能看出:

[-Infinity,-1)  已经看不到了

(1,+Infinity] 已经看不到了

 [-1,1] 

重点看[-1,1]这个区间 , 其他两个的View都已经看不到了~~


假设现在ViewPager在A页现在滑出B页,则:

A页的position变化就是( 0, -1]

B页的position变化就是[ 1 , 0 ]

知道了我们滑动时position的变化~~那么就开始设计我们的个性的切换效果;

官方给的例子,有变化透明度、偏移量、缩放的,我们准备来个不一样的,我们变化角度,即rotation;

大概的效果是这样的:


下面我们分析代码:

我们设置View的旋转中心为:

ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);
ViewHelper.setPivotY(view, view.getMeasuredHeight());

依然是ViewPager在A页现在滑出B页

那么A页应当在滑动过程中0度到-20度的偏移,B页应当在滑动过程中+20度到0度的偏移

结合

A页的position变化就是( 0, -1]

B页的position变化就是[ 1 , 0 ]

那么旋转的角度即:mRot = (20 * position); A页 mRot :0 ,~ -20 ; B页 mRot :20 ~ 0  ;

瞬间觉得好简单:

完整代码:

[java]  view plain copy
  1. package com.zhy.view;  
  2.   
  3. import com.nineoldandroids.view.ViewHelper;  
  4.   
  5. import android.annotation.SuppressLint;  
  6. import android.support.v4.view.ViewPager;  
  7. import android.util.Log;  
  8. import android.view.View;  
  9.   
  10. public class RotateDownPageTransformer implements ViewPager.PageTransformer  
  11. {  
  12.       
  13.     private static final float ROT_MAX = 20.0f;  
  14.     private float mRot;  
  15.       
  16.   
  17.       
  18.     public void transformPage(View view, float position)  
  19.     {  
  20.   
  21.         Log.e("TAG", view + " , " + position + "");  
  22.   
  23.         if (position < -1)  
  24.         { // [-Infinity,-1)  
  25.             // This page is way off-screen to the left.  
  26.             ViewHelper.setRotation(view, 0);  
  27.   
  28.         } else if (position <= 1// a页滑动至b页 ; a页从 0.0 ~ -1 ;b页从1 ~ 0.0  
  29.         { // [-1,1]  
  30.             // Modify the default slide transition to shrink the page as well  
  31.             if (position < 0)  
  32.             {  
  33.   
  34.                 mRot = (ROT_MAX * position);  
  35.                 ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);  
  36.                 ViewHelper.setPivotY(view, view.getMeasuredHeight());  
  37.                 ViewHelper.setRotation(view, mRot);  
  38.             } else  
  39.             {  
  40.   
  41.                 mRot = (ROT_MAX * position);  
  42.                 ViewHelper.setPivotX(view, view.getMeasuredWidth() * 0.5f);  
  43.                 ViewHelper.setPivotY(view, view.getMeasuredHeight());  
  44.                 ViewHelper.setRotation(view, mRot);  
  45.             }  
  46.   
  47.             // Scale the page down (between MIN_SCALE and 1)  
  48.   
  49.             // Fade the page relative to its size.  
  50.   
  51.         } else  
  52.         { // (1,+Infinity]  
  53.             // This page is way off-screen to the right.  
  54.             ViewHelper.setRotation(view, 0);  
  55.         }  
  56.     }  
  57. }  

你没看错,if else 里面代码是一样的,为了好理解特意没有合并到一起~~~

 

到此,我们从setPageTransformer使用,到修改ViewPager做到向下兼容,直至自己定义出个性的切换效果 都已经介绍完毕~~

大家可以发挥自己的创造力,做出各种神奇的动画效果,ok,就到这里!

如果你喜欢自定义ViewPager来实现,请移步:Android 自定义 ViewPager 打造千变万化的图片切换效果



源码点击下载


原文地址:http://blog.csdn.net/lmj623565791/article/details/40411921

更多相关文章

  1. android 下动画结束时闪烁问题
  2. 解决:android Listview 拖动时背景为黑色问题
  3. Android(安卓)最完善的自定义Banner轮播图之一,带给你最全面的体
  4. Android微信登录、分享功能实例
  5. Android支持USB摄像头
  6. Android平台值得关注的开源项目
  7. Android(安卓)实现指南针效果
  8. Android使用xml自定义软键盘效果(附源码)
  9. 深入探索 Android(安卓)包体积优化(匠心制作二)

随机推荐

  1. Android切换Activity时的淡入动画和缩小
  2. AndroidのViewFlipper和ViewPager
  3. 移动应用界面原型构建工具,交互设计师的利
  4. Android(安卓)requires compiler complia
  5. LinearLayout中添加分割线
  6. Android 中关于PathEffect子类的效果(中级
  7. android 水平滚动源码
  8. Android主流机型分辨率总结
  9. android 4.4 MT(去电)流程
  10. Android的五种布局