Android为ViewPager增加切换动画——使用属性动画

转载请注明出处:http://blog.csdn.net/allen315410/article/details/44200623

ViewPager作为Android最常用的的组件之一,相信大家在项目中会频繁的使用到的,例如利用ViewPager制作引导页、轮播图,甚至做整个app的表现层的框架等等。

Android3.0以下不支持切换动画

但是在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,运行如下,看起来很普通很死板:

支持Android3.0以上的官方方法

值得庆幸的是,Google在Android3.0以上的版本中增加了给ViewPager设置切换动画的API,允许开发者在Android3.0以上版本的应用中为ViewPager增加动画切换效果,这样就可以让ViewPager的切换效果变的绚丽点了,为ViewPager添加动画效果的API如下:

 public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer){...}

其中第一个参数boolean类型设置true就好,第二个参数PageTransformer就是我们自定义好的动画效果:

mViewPager = (ViewPager) findViewById(R.id.viewpager);
mViewPager.setPageTransformer(true, new ZoomOutPageTransformer());

其中ZoomOutPageTransformer的代码来自于google的training文档中,英文好的朋友可以直接进入文档查看,链接是

http://developer.android.com/training/animation/screen-slide.html

源码如下:

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以下的版本

前面我们说过的,Android3.0以下版本是不支持ViewPager增加切换动画的,原因很简单,我们可以参考一下上面贴出的两段代码,可以看到两段代码中都是使用了Android的属性动画写的切换效果,我们知道Android属性动画是在Android3.0才出来的特性,仅支持Android3.0及其以上版本,所以ViewPager的切换动画在Android3.0以下的版本中就不会支持了。分析出了不能在Android3.0以下版本中添加动画的原因后,我们就可以通过其它的方法来解决这个兼容性的问题了。

还记得之前我们在博客中就聊过老外的一个大牛——JakeWharton,对的,这个大牛在GitHub开源了自己为Android3.0以下系统添加属性动画的项目——NineOldAndroids,我们可以下载源码或者jar导入到我们的工程中来,用它来兼容我们的Android3.0以下的版本。

JakeWharton的主页是:https://github.com/JakeWharton

NineOldAndroids的主页是:https://github.com/JakeWharton/NineOldAndroids

下面就是我在DepthPageTransformer类中将View换成NineOldAndroids下的ViewHelper后,修改可以兼容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的源码,然后拷贝到工程中,重新命名一下,将里面的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切换动画的效果就出现了。

分析动画源码,实现自己的动画效果

上面的动画源码是我在Google的官方文档中找到的,里面完整的实现了一个系列动画的功能。那么我们是不是可以也能通过分析一下Google文档中源码的写法,找到规律后,我们自己动手实现一个自己的动画效果呢?先来看一下DepthPageTransformer.java这段源码,这个类实现了一个接口ViewPager.PageTransformer,重写了其中的一个方法

public void transformPage(View view, float position) {
	...
	Log.i("TAG", "view = " + view + ",position = " + position);
        ...
}

如上所示,我先在这个方法中打印出方法中的参数view对象和position的值,然后我们来看一下LOG的输出:

好,我们看LOG输出日志,可以看到有2个view对象在不停交错的输出,其中我选中标注的view的哈希值是4054c260,未选中标注的view的哈希值是4054c548,然后再来看一下position的值,可以注意的是,4054c260的view的position值从0.0一直不断减小到-1.0,4054c548的view的position的值从1.0一直不断减小到0.0,我们为了方便,记哈希值为4054c260的view为A页,记哈希值为4054c548的view为B页。

情景分析一下,也请一边看一下DepthPageTransformer.java的源码;

当position < -1,此时position均不代表A页和B页的位置,所以这里我们不做任何的动画出来。

当position <= 0,此时position的范围是在0.0 ~-1.0之间,可以认为这是代表A页的运动轨迹,也就是A页移出屏幕外。

当position <= 1,此时position的范围是在1.0 ~ 0.0之间,可以认为这是代表B页的运动轨迹,也就是B页移到屏幕上。

当position > 1,此时position均不代表A页和B页的位置,所以这里我们不做任何的动画出来。

好了,通过我们的分析可知,我们实现动画效果是根据position的变化来设定的。那么,我们现在也要根据position来实现一个自己的ViewPager的动画效果了,我们做一个ViewPager的旋转移出屏幕和旋转移到屏幕上的效果吧。草图如下所示:

看着草图,我们想象一下,当手指向左滑动的时候,A页会旋转一定的角度移出屏幕,B页也会旋转一定的角度移到屏幕上,那么我们就先给移动的角度设置一个常量吧,这里我假设旋转的最大角度是20度了,以下是我的源码:

/**
 * 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);
		}
	}
}

效果图就在上面哦,看起来还凑合吧,根据上面的描述,只要你知道属性动画的相关api,也可以自定义初各种各样的动画效果出来,可以将多种单一的动画效果混合在一起使用,让ViewPager的滑动效果看起来更加的“复杂”。

感谢CSDN博客专家鸿洋无私奉献的教程,教程视频地址:http://www.imooc.com/learn/226

源码请在这里下载

时间: 2024-10-12 03:57:37

Android为ViewPager增加切换动画——使用属性动画的相关文章

Android为ViewPager增加切换动画——自定义ViewPager

转载请注明出处:http://blog.csdn.net/allen315410/article/details/44224517 在上篇博客中,我写了一个使用属性动画为ViewPager添加切换动画的方法,并且可以兼容到Android3.0以下版本的设备上,那么关于为ViewPager添加动画的方式还会有另外一种实现方案,就是自定义一个自己带动画效果的ViewPager,关于上篇博客,还没来得及查看的朋友可以点击这里进行查看.下面,我们将新建一个工程,来说说怎样自定义一个自带切换动画效果的Vi

Android动画:模拟开关按钮点击打开动画(属性动画之平移动画)

在Android里面,一些炫酷的动画确实是很吸引人的地方,让然看了就赏心悦目,一个好看的动画可能会提高用户对软件的使用率.另外说到动画,在Android里面支持两种动画:补间动画和属性动画,至于这两种动画的区别这里不再介绍,希望开发者都能在使用的过程中体会两者的不同. 本文使用属性动画完成,说到属性动画,肯定要提到 JakeWharton大神写的NineOldAndroids动画库,如果你的app需要在android3.0以下使用属性动画,那么这个库就很有作用了,如果只需要在高版本使用,那么直接

Android动画之属性动画

当我们看到别人的APP里面或者写的Demo里面的一些很牛逼得动画效果的时候,是否会有那么一种冲动我要看看它的源代码到底是怎么写的,为毛我就是写不出这样的动画效果呢,为毛我只能做哪些简单的平移,缩放,旋转,透明度改变的动画效果呢.呵呵,当你这么想的时候,证明你应该存在两种主要的问题:第一,就是你的确基础知识不过关,别人用到的东西,你根本就没有接触过,但是这些东西的确是API里面确实存在的东西.第二,就是你的经验不够,逻辑思维能力还有待提升.任何一个很酷很炫的动画效果,都应该是由一系列的动画效果合成

Android开发实战之补间动画和属性动画

说起动画,其实一点也不陌生,在使用一款app的时候为了优化用户体验,多多少少的,都会加入动画. 安卓中的动画,分为两大类:补间动画和属性动画.本篇博文会详细介绍总结这两大动画,希望本篇博文对你的学习和生活有所帮助. **补间动画** 补间动画分为四类:平移动画,旋转动画,缩放动画和渐变动画.这几类动画用法都差不多,只是对象参数不同这里我统一展示出来.以下是效果图: 实现代码很简单: btn1.setOnClickListener(new View.OnClickListener() { @Ove

Android动画学习(缓动动画与属性动画的区别)

前言: 在 Android动画学习(概述)中,如果你看过这篇帖子,你应该会对缓动动画和属性动画之间的区别产生疑问,因为在它们的应用中,你会感觉这两种动画有着一些相似的地方,为此,我打算把这两种动画之间的区别做一下说明 区别: 在这里先附上官方文档对于这两种动画的区别说明(我所说的缓动动画对应在下文中的英文为:View Animation,属性动画对应在下文中的英文为:Property Animation): How Property Animation Differs from View Ani

安卓中的动画之属性动画(1)

属性动画(Property Aniamtion)是在谷歌新推出的一种动画. 1.什么是属性动画? 属性动画,顾名思义,就是操作属性的动画.在这里可能有人要问什么是操作的属性?想想以前我们学习的动画--变换动画,可以更改动画显示的各种形态,看上去非常炫酷:布局动画,可以更改activity跳转你的动画:帧动画,就是flash动画一样.我们在使用这些动画时,特别是变换动画时,有没有想过,假如一个imageview有一个监听事件,而我们使用变换动画更换了imageview的位置时,此时我们想要实现这个

android 为viewPager增加动画切换效果

在android应用开发中,viewPager可以实现很多炫丽的切换功能,如banner无限广告滚动条.新手引导等都用得到,使用频率不言而喻.依赖谷歌提供的辅助代码,viewPager的切换效果还可以更加出彩,实现过程也相当地简单. 先在浏览器中输入谷歌提供的网址,链接如:http://developer.android.com/training/animation/screen-slide.html ,如不能流畅打开,你最好准备一个翻墙工具,保留备需. 在网站中你可以看到viewPager的一

Android之Fragment,帧动画,补件动画,属性动画

Fragment: 在安卓手机越来越大的情况下,一个屏幕显示只显示一个内容,会显得空旷,布局不够好看,屏幕利用的也不够充分.通常在平板中会出现这种情况,但是由于现在的手机屏幕越来越大,所以在3.0之后引入了Fragment.也可以使用支持类库,来向下兼容低版本.它的生命周期方法和activity一样 使用Fragment可以让我们更加充分地利用手机的屏幕空间,他可以在一个activity中有多个Fragment,多个Fragment可以显示不同的内容. 我们通过简单的demo来了解什么是Frag

android中的动画之属性动画(3)

我在这里将说下关于属性动画中的多个动画同时,在之前我们知道可以在xml代码中的set元素下设置android:ordering属性来控制动画的同时发生.这里我将说的是在JAVA代码中,怎么实现动画同时发生,有两种方法. 1.通过多个ObjectAnimator对象来实现 1 ObjectAnimator.ofFloat(imageview, "translationY", 0F, 100F).setDuration(1000).start(); 2 ObjectAnimator.ofF