View的坐标体系
1、原点在屏幕左上角
2、View常用属性
属性 | 含义 | 描述 |
---|---|---|
mLeft、mTop、mRight、mBottom | 以 Parent的左上角为参考 原点 | |
width | = mRight - mLeft | |
height | = mBottom - mTop | |
getTranslationX() getTranslationY() |
位移 | 默认值是0 |
mX、mY | mX = mLeft + getTranslationX(); mY = mTop + getTranslationY(); |
View左上角相对于Parent容器的坐标 |
mScrollX | 相对View的左边缘,在X轴方向的偏移量 | |
mScrollY | 相对View的上边缘,和Y轴方向的偏移量 | |
MotionEvent.ACTION_DOWN | 手指按下屏幕 | |
MotionEvent.ACTION_MOVE | 手指在屏幕移动 | |
MotionEvent.ACTION_UP | 手指离开屏幕 | |
event.getX() event.getY() |
手指 相对当前View左上角 的 x、y坐标 | |
event.getRawX() event.getRawY() |
手指 相对于手机屏幕左上角 的x、y坐标 |
3、mTouchSlop
系统能识别的被认为是 滑动的最小距离
手指在屏幕移动距离 小于 mTouchSlop,不认为是滑动
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
处理滑动时,用这个常量过滤未达到这个临界值的移动行为
4、VelocityTracker 速度追踪
追踪手指滑动的速度,包括水平和竖直方向的速度
-
在 View 的 onTouchEvent 方法,追踪当前单击事件的速度
VelocityTracker velocityTracker = new VelocityTracker.obtain(); velocityTracker.addMovement(event);
-
获取当前滑动速度
//计算速度 1000 表示计算1000ms内手指滑过的像素数 velocityTracker.computeCurrentVelocity(1000); int xVelocity = (int) velocityTracker.getXVelocity(); int yVelocity = (int) velocityTracker.getYVelocity();
速度指一段时间内手指滑过的像素数。
速度可以为负数,从右往左滑,水平方向速度为负值。
速度 = (终点位置 - 起点位置) / 时间段 -
不需要使用时,重置并回收内存
velocityTracker.clear(); velocityTracker.recycle();
5、GestureDetector
手势检测,辅助检测用户的单击、滑动、长按、双击等行为。
-
创建GestureDetector 对象,并实现 OnGestureListener 接口
根据需要可以实现 OnDoubleTapListener 监听双击行为 //手势监听 GestureDetector detector = new GestureDetector(GestureDetector.OnGestureListener); //监听双击行为 detector.setOnDoubleTapListener(GestureDetector.OnDoubleTapListener); //解决长按屏幕后无法拖动的现象 detector.setIsLongpressEnabled(false);
-
在View 的 onTouchEvent 中添加实现
boolean consume = detector.onTouchEvent(event); return consume;
-
监听方法介绍
1) OnGestureListener的方法方法 描述 onDown 手指触摸屏幕的瞬间,由1个ACTION_DOWN 触发 onShowPress 手指轻触屏幕尚未松开和拖动,由1个ACTION_DOWN触发
和onDown的区别是,它是没有松开和拖动的状态onSingleTapUp 手指轻触屏幕后松开,伴随1个ACTION_UP触发,单击行为 onScroll 手指按下屏幕并拖动,由1个ACTION_DOWN、多个ACTION_MOVE 触发,拖动行为 onLongPress 长按屏幕不放 onFling 按下屏幕、快速滑动后松开。
由1个ACTION_DOWN,多个ACTION_MOVE、1个ACTION_UP触发
快速滑动行为2) OnDoubleTapListener的方法
方法 描述 onDoubleTap 双击。由两次连续的单击组成。不会与 onSingleTapConfirmed 共存 onSingleTapConfirmed 严格的单击行为
与 onSingleTapUp 的区别:如果触发了 onSingleTapConfirmed
那么后面不可能再紧跟另一个单击行为。
只可能是单击,不可能是双击中的一次单击onDoubleTapEvent 表示发生了双击行为,
在双击期间,ACTION_DOWN、ACTION_MOVE、ACTION_UP 都会触发此回调。
6、Scroller 弹性滑动对象
用于实现View 的弹性滑动
View滑动的几种方式,使用 ScrollTo/ScrollBy、使用动画、改变布局参数
1、scrollTo/scrollBy 瞬间完成,没有过渡效果
scrollTo/scrollBy,滑动的是View的内容,并不能滑动View本身。
-
scrollBy(x, y) 相对当前位置的滑动
内部调用 scrollTo 方法,scrollTo(mScrollX + x, mScrollY + y) -
scrollTo(x, y) 基于所传递参数的绝对滑动
【滑动时,mScrollX,mScrollY的改变规则】
View边缘:指View的位置,由四个顶点组成
View内容边缘:指View中的内容的边缘
mScrollX:== View左边缘与View内容左边缘,在水平方向的距离
mScrollY:== View上边缘与View内容上边缘,在竖直方向的距离
scrollTo、scrollBy,只能改变View内容的位置,不能改变View在布局中的位置
当View左边缘在View内容左边缘的右边时,mScrollX为正值,反之为负值
(从左向右滑动,mScrollX为负值,反之为正值)
当View上边缘在View内容上边缘的下边时,mScrollY为正值,反之为负值
(从上往下滑动,mScrollY为负值,反之为正值)
2、使用动画
操作 View的 translationX 和 translationY 属性。
属性动画,改变的是View的属性
ObjectAnimator.ofFloat(targetView, “translationX”, 0, 100).setDuration(100).start();
View动画操作的是View的影像
View动画,要把fillAfter设置为true,否则在动画结束后会恢复到动画前状态
3、改变布局参数
改变 LayoutParams
View滑动实现 | 实现方式 |
---|---|
ScrollTo/ScrollBy | scrollTo/scrollBy,滑动的是View的内容,并不能滑动View本身 scrollBy(x, y) 相对当前位置的滑动 内部调用 scrollTo 方法,scrollTo(mScrollX + x, mScrollY + y) scrollTo(x, y) 基于所传递参数的绝对滑动 |
使用动画 | 属性动画,改变View的属性 ObjectAnimator.ofFloat(targetView, “translationX”, 0, 100).setDuration(100).start(); View动画操作View的影像 View动画,要把fillAfter设置为true,否则在动画结束后会恢复到动画前状态 |
改变布局参数 |
弹性滑动的原理及实现
1、使用Scroller
Scroller mScroller = new Scroller(context);
//缓慢滚动到指定位置
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
/* 1000ms内滑向destX,效果是慢慢滑动
* startScroll()只是保存了传递的几个参数
* 参数一:滑动的起点x
* 参数二:滑动的起点y
* 参数三:要滑动的距离dx
* 参数四:要滑动的距离dy
* 参数五:滑动时间
*/
mScroller.startScroll(scrollX, 0, delta, 0, 1000);
invalidate();//重绘,触发onDraw(),onDraw中会调用computeScroll()
}
@Override
public void computeScroll() {
/* computeScrollOffset()
* 这个方法会根据时间的流逝百分比,计算当前的scrollX和scrollY的值,
* 返回true,表示滑动还未结束,false表示滑动已结束
*/
if(mScroller.computeScrollOffset()) {
//获取 mScroller当前的scrollX,scrollY,通过scrollTo方法实现滑动到新位置
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
滑动执行过程: