转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/40411921 ,本文出自: 【张鸿洋的博客】

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 plaincopy
  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. <android.support.v4.view.ViewPager
  6. android:id="@+id/id_viewpager"
  7. android:layout_width="fill_parent"
  8. android:layout_height="fill_parent" />
  9. </RelativeLayout>

2、MainActivity

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

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

3、PageTransformer

ViewPager有个方法叫做:

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

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

1、DepthPageTransformer

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

调用代码:

[java] view plaincopy
  1. mViewPager.setPageTransformer(true, new DepthPageTransformer());

效果:

2、ZoomOutPageTransformer

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

调用代码:

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

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

为什么呢?

我们再去看看setPageTransformer的源码:

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

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

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

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

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

源码点击下载

---------------------------------------------------------------------------------------------------------

博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

1、高仿微信5.2.1主界面及消息提醒

2、高仿QQ5.0侧滑

Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)相关推荐

  1. Android -- ViewPager切换动画,PageTransformer

    transformPage(View view, float position) view就是滑动中的那个view,position这里是float类型,是当前滑动状态的一个表示,比如当滑动到正全屏时 ...

  2. Android项目实战(四):ViewPager切换动画(3.0版本以上有效果)

    原文:Android项目实战(四):ViewPager切换动画(3.0版本以上有效果) 学习内容来自"慕课网" 一般APP进去之后都会有几张图片来导航,这里就学习怎么在这张图片切换 ...

  3. Android使用ActionBar和ViewPager切换页面

    演示效果如下:  项目布局如下:    MainActivity.java代码 <code class="hljs java has-numbering" style=&qu ...

  4. android 自定义酷炫ViewPager切换效果

    Android 自定义特效酷炫ViewPager切换效果,当ViewPager切换时,下面的自定义页面标识图也跟着做动画切换, 效果图如下: 具体代码如下: 自定义ViewPager适配器如下: pa ...

  5. Android 编程下设置 Activity 切换动画

    为 Activity 设置切换动画 我们知道,我们可以在 AndroidManifest.xml 文件中,通过 android:theme 属性设置 Activity 的主题.主题中定义了关于 Act ...

  6. android 设置全局的页面切换动画问题

    这两天在看android 设置页面切换动画,看的很纠结,晕菜了 我这里有四个手机, 一加 版本  5.1.1   小米2s  版本 5.0 华为P6   版本    4.4.2   酷派版本   4. ...

  7. unity调用 Android 分享图片文字 方法 不需要第三方sdk 兼容android7.0+

    直接说方法把,在Android Studio中 新建一个工程,新建时选择Add No Activity,包名跟unity中设置的一样比如这里用 come.demo.share 在res目录下新建个文件 ...

  8. Android 在线下载更新App 下载完成安装APK(兼容Android7.0)

    先上图: 首先对android7.0的打开文件方式进行适配 使用FileProvider 第一步: 在AndroidManifest.xml清单文件中注册provider,因为provider也是An ...

  9. Android 动画之View动画效果和Activity切换动画效果

    View动画效果: 1.>>Tween动画 通过对View的内容进行一系列的图形变换(平移.缩放.旋转.透明度变换)实现动画效果,补间动画需要使用<set>节点作为根节点,子节 ...

最新文章

  1. 氮化镓充电器哪家好_双十二推荐入手的热门氮化镓充电器
  2. 走向公共管理的治理理论
  3. oracle数据泵还原命令,Oracle Linux环境中使用数据泵的形式还原Oracle数据库
  4. spring定时任务时间格式cronExpression设置
  5. 微软应用商店_微软自家的软件也放弃Windows 10
  6. 后置通知(After Advice)
  7. L1-048. 矩阵A乘以B
  8. phpstorm 的下载、安装与激活
  9. POJ 3268 Silver Cow Party 单向最短路
  10. LCA(最近公共子序列)
  11. python离线翻译软件哪个好用_哪个翻译软件最好用?
  12. 自由软件、开源软件、免费软件之间的区别
  13. 数据库分区分片(Shards)技术概览
  14. 员工转正述职答辩问什么问题_新员工转正述职答辩.ppt
  15. Unity插件 - MeshEditor(九) 模型涡流扭曲特效(黑洞吸引特效)
  16. findfont: Font family ['DejaVu Sans'] not found. Falling back to DejaVu Sans.
  17. java基础回顾-day01
  18. 【Unity】新手初学Animation实现人物移动
  19. JavaScript简单随机数去重
  20. 自考哪些专业不考英语跟计算机,深圳自考有哪些专业?并且可以不考“数学”和“英语”!...

热门文章

  1. 几种线程安全的Map解析
  2. Apache MPM介绍
  3. python 矩阵操作
  4. 优秀课程案例:图形化编程画圆方法汇总
  5. 作为shopee新手卖家的你,如何快速出单?不得不看的shopee店铺装修技巧
  6. vue2.0运行导入的项目出现node:events:491 throw er; // Unhandled ‘error‘ event错误提示解决办法
  7. centos永久性挂载硬盘
  8. 《那一世·你我所见的榕桦》·亡灵之歌
  9. apple并不神秘,但是很无耻(事件介绍)
  10. autocad.net计算图案填充的周长