android仿美丽说登录拖拽Layout
2015-09-17 18:19
656 查看
好久没有写博客了,今天趁自己不是很忙,有看到美丽说app的登录页面有一个挺有新意的小交互,就模仿了一下,基本上和它的功能完全一样。下面先看下效果图。
![](http://img.blog.csdn.net/20150917180627517)
功能描述:手指在自定义的 View上滑动时,如果滑动距离超过指定距离,或者滑动速度超过指定的速度时,开始滑动。添加了滑到到顶部和底部的滑动监听。
代码如下:
总结:可以继承自任意一个Layout去重写,个人比较喜欢用RelativeLayout,主要重写其 onTouchEvent修改其子View的偏移量即可。
DEMO下载
功能描述:手指在自定义的 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下载
相关文章推荐
- Android studio改变字体大小
- Android 动画之TranslateAnimation应用详解
- Android Asynctask
- Android wakelock
- Android xml中定义的shape与Drawable之间的关系
- Android: Service中创建窗口显示
- android系统平台显示驱动开发简要:LCD常用接口篇『二』
- ViewPager的setOnPageChangeListener过时。
- Android自定义对话框去掉白色边框
- Android 单元测试搭建
- 12.Android AsyncTask 技巧
- Android 杀掉进程
- android 获取一些系统指定路径的方法整理
- android JSON数据解析
- Android视频缩略图(二)
- 解决android开发在大屏手机图片出现内存溢出
- Android 事件分发机制测试以及总结
- Android判断GPS是否开启和强制帮用户打开GPS
- Android开发时,提示no resource for "theme......."in package "android"
- Unable to execute dex: Multiple dex files define Landroid/support/v4/accessi问题解决