android仿美丽说登录拖拽Layout

   好久没有写博客了,今天趁自己不是很忙,有看到美丽说app的登录页面有一个挺有新意的小交互,就模仿了一下,基本上和它的功能完全一样。下面先看下效果图。

  

   功能描述:手指在自定义的 View上滑动时,如果滑动距离超过指定距离,或者滑动速度超过指定的速度时,开始滑动。添加了滑到到顶部和底部的滑动监听。

   代码如下:


package view;
/**
 * @description 仿美丽说底部拖拽效果
 * @author rzq
 * @date 2015年9月17日
 */
public class DragLayout extends RelativeLayout
{
	/**
	 * 速度常量
	 */
	private static final int SNAP_VELOCITY = 800;

	/**
	 * 要被拖拽的View
	 */
	private View mContentView;

	/**
	 * 底部外漏高度
	 */
	private int bottomFlexHeight = 50;
	/**
	 * 最大可偏移Y
	 */
	private int mMaxtranslationY;
	/**
	 * 可识别触摸事件的高度
	 */
	private int touchHeight = 60;

	/**
	 * 是否需要处理触摸事件
	 */
	private boolean isDeal;

	/**
	 * 速度追踪对象 
	 */
	private VelocityTracker velocityTracker;

	private ScrollTopListener mTopListener;
	private ScrollBottomListener mBottomListener;

	public DragLayout(Context context)
	{
		this(context, null);
	}

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

	@Override
	protected void onFinishInflate()
	{
		// 拿到唯一的contentView
		mContentView = getChildAt(0);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b)
	{
		super.onLayout(changed, l, t, r, b);
		/**
		 * 整个布局layout后,将contentview移到底部
		 */
		mMaxtranslationY = mContentView.getHeight() - bottomFlexHeight;
		mContentView.setY(mMaxtranslationY);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		super.onTouchEvent(event);

		addVelocityTracker(event);
		switch (event.getAction())
		{
		case MotionEvent.ACTION_DOWN:
			float downX = event.getX();
			float downY = event.getY();
			if (!isInRect(downX, downY))
			{
				isDeal = false;
			}
			else
			{
				isDeal = true;
			}

			break;
		case MotionEvent.ACTION_MOVE:
			if (isDeal)
			{
				float moveY = event.getY();
				if (moveY >= 0)
				{
					mContentView.setY(moveY);
				}
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			int velocityY = getScrollYVelocity();
			if (isDeal)
			{
				if (mContentView.getTranslationY() < (mMaxtranslationY / 2))
				{
					if (velocityY > SNAP_VELOCITY)
					{
						scrollToBottom();
					}
					else
					{
						// 属性动画移动到Top
						scrollToTop();
					}
				}
				else
				{
					// 向上的速度足够,也向上滑
					if (velocityY <= -SNAP_VELOCITY)
					{
						scrollToTop();
					}
					else
					{
						// 属性动画移动到下面
						scrollToBottom();
					}
				}
			}
			isDeal = false;
			recycleVelocityTracker();
			break;
		}
		return true;
	}

	private void scrollToTop()
	{
		ObjectAnimator topAnimation = ObjectAnimator.ofFloat(mContentView, "translationY",
				mContentView.getTranslationY(), 0);
		if (mTopListener != null)
		{
			topAnimation.addListener(new AnimatorListenerAdapter()
			{
				@Override
				public void onAnimationEnd(Animator animation)
				{
					mTopListener.onScrollTop();
				}
			});
		}
		topAnimation.start();
	}

	private void scrollToBottom()
	{
		ObjectAnimator bottomAnimation = ObjectAnimator.ofFloat(mContentView, "translationY",
				mContentView.getTranslationY(), (mMaxtranslationY));
		if (mBottomListener != null)
		{
			bottomAnimation.addListener(new AnimatorListenerAdapter()
			{
				@Override
				public void onAnimationEnd(Animator animation)
				{
					mBottomListener.onScrollBottom();
				}
			});
		}
		bottomAnimation.start();
	}

	/**
	 * 判断按下的点是否在指定区域内,不在区域内不做处理
	 */
	private boolean isInRect(float downX, float downY)
	{
		if (downX > mContentView.getLeft() && downX < mContentView.getRight())
		{
			if (downY >= mContentView.getTranslationY() && downY <= mContentView.getTranslationY() + touchHeight)
			{
				return true;
			}
		}
		return false;
	}

	/** 
	 * 添加用户的速度跟踪器 
	 */
	private void addVelocityTracker(MotionEvent event)
	{
		if (velocityTracker == null)
		{
			velocityTracker = VelocityTracker.obtain();
		}
		velocityTracker.addMovement(event);
	}

	/** 
	 * 移除用户速度跟踪器 
	 */
	private void recycleVelocityTracker()
	{
		if (velocityTracker != null)
		{
			velocityTracker.recycle();
			velocityTracker = null;
		}
	}

	/** 
	 * 获取Y方向的滑动速度 
	 */
	private int getScrollYVelocity()
	{
		velocityTracker.computeCurrentVelocity(1000);
		int velocity = (int) velocityTracker.getYVelocity();
		return velocity;
	}

	public void setmTopListener(ScrollTopListener mTopListener)
	{
		this.mTopListener = mTopListener;
	}

	public void setmBottomListener(ScrollBottomListener mBottomListener)
	{
		this.mBottomListener = mBottomListener;
	}

	/**
	* @description 滑动到底部事件监听
	* @author rzq
	* @date 2015年9月17日
	 */
	public interface ScrollBottomListener
	{
		public void onScrollBottom();
	}

	/**
	* @description 滑动到顶部事件监听
	* @author rzq
	* @date 2015年9月17日
	 */
	public interface ScrollTopListener
	{
		public void onScrollTop();
	}
}

   总结:可以继承自任意一个Layout去重写,个人比较喜欢用RelativeLayout,主要重写其 onTouchEvent修改其子View的偏移量即可。

   DEMO下载

猜你喜欢

转载自blog.csdn.net/lcq5211314123/article/details/48525257
今日推荐