Android ViewPager Parallax视觉差切换动画

转载请标明原地址:http://blog.csdn.net/gaolei1201/article/details/50428553

ViewPager 我们比较常用,但是它的切换只有水平滚动着一种方式。最求个性化的现代社会,我么怎么把它打造地个性化些呢?没有你做不到的只有你想不到的,呵呵。 

切换动画有两种实现方式:

1.ViewPager自带了一个setPageTransformer用于设置切换动画,本篇先不讲这种方法,有关详情可参考:http://blog.csdn.net/lmj623565791/article/details/40411921   。

2.自定义动画 ,github上有开源项目地址:https://github.com/jfeinstein10/JazzyViewPager 。这种方法需要注意的是,利用View的Animation。所以ViewPager中的内容只能是View,不能是Fragment等非View控件。这篇文章主要是在开源项目的基础上制作几种比较实用的切换动画。

第2种方法实现的原理:

获取用户切换时当前View和切换至的目的View。

ViewPager也需要监听用户的手势,所以肯定提供了某个方法。于是纵观ViewPager的方法,发现了一个叫做 onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法。没错就是这个方法:在页面滚动时调用~

下面仔细研究下这几个参数:

在非第一页与最后一页时,滑动到下一页,position为当前页位置;滑动到上一页:position为当前页-1

positionOffset 滑动到下一页,[0,1)区间上变化;滑动到上一页:(1,0]区间上变化,

positionOffsetPixels这个和positionOffset很像:滑动到下一页,[0,宽度)区间上变化;滑动到上一页:(宽度,0]区间上变化,

第一页时:滑动到上一页position=0 ,其他基本为0 ;最后一页滑动到下一页 position为当前页位置,其他两个参数为0,

豁然发现,我们需要的步骤的第二步解决了,positionOffset很适合作为,渐变,缩放的控制参数;positionOffsetPixels则可以作为平移等的控制参数。

第一种切换动画  "左侧覆盖"  效果:



自定义ViewPager,主要代码:

<span style="font-size:14px;"><span style="font-size:14px;">public class MyJazzyViewPager extends ViewPager {
	private float mTrans;
	private float mScale;
	private static final float SCALE_MAX = 0.5f;
	private static final String TAG = "MyJazzyViewPager";
	private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();
	private View mLeft;
	private View mRight;

	public MyJazzyViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public void onPageScrolled(int position, float positionOffset,
			int positionOffsetPixels) {

		// Log.e(TAG, "position=" +
		// position+", positionOffset = "+positionOffset+" ,positionOffsetPixels =  "
		// + positionOffsetPixels+" , currentPos = " + getCurrentItem());
		float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
		mLeft = findViewFromObject(position);
		mRight = findViewFromObject(position + 1);
		animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
		super.onPageScrolled(position, positionOffset, positionOffsetPixels);
	}

	public void setObjectForPosition(View view, int position) {
		mChildrenViews.put(position, view);
	}
	public View findViewFromObject(int position) {
		return mChildrenViews.get(position);
	}

	private boolean isSmall(float positionOffset) {
		return Math.abs(positionOffset) < 0.0001;
	}

	protected void animateStack(View left, View right, float effectOffset,
			int positionOffsetPixels) {
		if (right != null) {
			/**
			 * 缩小比例 如果手指从右到左的滑动(切换到后一个):0.0~1.0,即从一半到最大
			 * 如果手指从左到右的滑动(切换到前一个):1.0~0,即从最大到一半
			 */

			mTrans = -getWidth() - getPageMargin() + positionOffsetPixels;
			// 利用nineoldandroid.jar控制右侧滑动动画
			ViewHelper.setTranslationX(right, mTrans);
		}
		if (left != null) {
			left.bringToFront();
		}
	}
}</span></span>


第一种切换动  "右侧覆盖"  效果:


自定义ViewPager代码如下:

<span style="font-size:14px;"><span style="font-size:14px;">public class MyJazzyViewPager extends ViewPager {
	private float mTrans;
	private float mScale;
	private static final float SCALE_MAX = 0.5f;
	private static final String TAG = "MyJazzyViewPager";
	private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();
	private View mLeft;
	private View mRight;
	public MyJazzyViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public void onPageScrolled(int position, float positionOffset,
			int positionOffsetPixels) {

		// Log.e(TAG, "position=" +
		// position+", positionOffset = "+positionOffset+" ,positionOffsetPixels =  "
		// + positionOffsetPixels+" , currentPos = " + getCurrentItem());

		float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;

		mLeft = findViewFromObject(position);
		mRight = findViewFromObject(position + 1);

		animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
		super.onPageScrolled(position, positionOffset, positionOffsetPixels);
	}

	public void setObjectForPosition(View view, int position) {
		mChildrenViews.put(position, view);
	}

	public View findViewFromObject(int position) {
		return mChildrenViews.get(position);
	}

	private boolean isSmall(float positionOffset) {
		return Math.abs(positionOffset) < 0.0001;
	}

	protected void animateStack(View left, View right, float effectOffset,
			int positionOffsetPixels) {
		Log.d("gaolei", "effectOffset----------------/" + effectOffset);
		Log.d("gaolei", "positionOffsetPixels----------------/"
				+ positionOffsetPixels);
		if (right != null) {
			/**
			 * 缩小比例 如果手指从右到左的滑动(切换到后一个):0.0~1.0,即从一半到最大
			 * 如果手指从左到右的滑动(切换到前一个):1.0~0,即从最大到一半 //
			 */

			right.bringToFront();
		}
		if (left != null) {
			mTrans = positionOffsetPixels;
			// 利用nineoldandroid.jar控制右侧滑动动画
			ViewHelper.setTranslationX(left, mTrans);
		}
	}
}</span></span>
第三种切换动画“左右都滑动”效果:


自定义ViewPager主要代码:

<span style="font-size:14px;"><span style="font-size:14px;">public class MyJazzyViewPager extends ViewPager {
	private float mTrans;
	private float mScale;
	/**
	 * 最大的缩小比例
	 */
	private static final float SCALE_MAX = 0.5f;
	private static final String TAG = "MyJazzyViewPager";
	/**
	 * 保存position与对于的View
	 */
	private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();
	private View mLeft;
	private View mRight;

	public MyJazzyViewPager(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public void onPageScrolled(int position, float positionOffset,
			int positionOffsetPixels) {

		// Log.e(TAG, "position=" +
		// position+", positionOffset = "+positionOffset+" ,positionOffsetPixels =  "
		// + positionOffsetPixels+" , currentPos = " + getCurrentItem());

		// 滑动特别小的距离时,我们认为没有动,可有可无的判断
		float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;

		// 获取左边的View
		mLeft = findViewFromObject(position);
		// 获取右边的View
		mRight = findViewFromObject(position + 1);

		// 添加切换动画效果
		animateStack(mLeft, mRight, effectOffset, positionOffsetPixels);
		super.onPageScrolled(position, positionOffset, positionOffsetPixels);
	}

	public void setObjectForPosition(View view, int position) {
		mChildrenViews.put(position, view);
	}

	/**
	 * 通过过位置获得对应的View
	 * 
	 * @param position
	 * @return
	 */
	public View findViewFromObject(int position) {
		return mChildrenViews.get(position);
	}

	private boolean isSmall(float positionOffset) {
		return Math.abs(positionOffset) < 0.0001;
	}

	protected void animateStack(View left, View right, float effectOffset,
			int positionOffsetPixels) {
		Log.d("gaolei", "effectOffset----------------/" + effectOffset);
		Log.d("gaolei", "positionOffsetPixels----------------/"
				+ positionOffsetPixels);
		if (right != null) {
			/**
			 * 缩小比例 如果手指从右到左的滑动(切换到后一个):0.0~1.0,即从一半到最大
			 * 如果手指从左到右的滑动(切换到前一个):1.0~0,即从最大到一半 /** x偏移量:
	 */
			right.bringToFront();
		}
		if (left != null) {
			mTrans = positionOffsetPixels;
			// 利用nineoldandroid.jar控制左侧滑动动画,修改200可以尝试改变移动距离
			ViewHelper.setTranslationX(left, positionOffsetPixels - 200
					* effectOffset);
		}
	}
}
</span></span>

               
   源码地址,点击下载......



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值