• 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文档中,英文好的朋友能够直接进入文档查看,链接是
    源代码例如以下:
    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添加切换动画的。原因非常easy,我们能够參考一下上面贴出的两段代码,能够看到两段代码中都是使用了Android的属性动画写的切换效果,我们知道Android属性动画是在Android3.0才出来的特性,仅支持Android3.0及其以上版本号,所以ViewPager的切换动画在Android3.0下面的版本号中就不会支持了。分析出了不能在Android3.0下面版本号中加入动画的原因后。我们就能够通过其他的方法来解决这个兼容性的问题了。
    还记得之前我们在博客中就聊过老外的一个大牛——JakeWharton,对的。这个大牛在GitHub开源了自己为Android3.0下面系统加入属性动画的项目——NineOldAndroids,我们能够下载源代码或者jar导入到我们的project中来。用它来兼容我们的Android3.0下面的版本号。

    JakeWharton的主页是:https://github.com/JakeWharton
    以下就是我在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的源代码,然后复制到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切换动画的效果就出现了。


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

    上面的动画源代码是我在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


    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    51Nod-1006【LCS】+【输出路径】模板题
    POJ 2250 Compromise【LCS】+输出路径
    洛谷 P1387 最大正方形 【dp】(经典)
    【hdu】4521 小明序列【LIS变种】【间隔至少为d】
    HDU 1025 城市供应 【LIS】
    hdu 2191 悼念512汶川大地震遇难同胞 【多重背包】(模板题)
    HDU 2159 FATE【二维完全背包】
    POJ 1384 Piggy-Bank【完全背包】+【恰好完全装满】(可达性DP)
    洛谷 P1474 货币系统 Money Systems(经典)【完全背包】+【恰好装满的最大方案数量】
    洛谷 P1057 传球游戏 【dp】(经典)
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4627891.html
Copyright © 2020-2023  润新知