View的事件体系总结
View是Android中所有控件的基类,是一种界面层的控件的一种抽象。
View基础知识
View的位置参数:top左上角纵坐标、left左上角横坐标、right右下角横坐标、bottom右下角纵坐标,相对于View的父容器来说,是一种相对坐标。
x、y是View左上角的坐标,translationX和translationY是View左上角相对于父容器的偏移量。View在平移时,top、left不改变,改变的是x、y、translationX、translationY。
MotionEvent:手指接触屏幕后所产生的一系列事件。通过点击对象可以得到点击事件发生的x和y坐标,getX/getY 相对于当前View 左上角的x和y坐标,getRawX/getRawY相对于手机屏幕左上角的x和y坐标。
TouchSlop:系统所能识别出的被认为是滑动的最小距离。
ViewConfiguration.get(getContext()).getScaledTouchSlop()
VelocityTracker:速度追踪,用于追踪手指在滑动过程中的速度。
VelocityTracker velocityTracker = VelocityTracker.obtain(); velocityTracker.addMovement(event); velocityTracker.computeCurrentVelocity(1000); int xVelocity = (int) velocityTracker.getXVelocity(); int yVelocity = (int) velocityTracker.getYVelocity();
GestureDetector:手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。
View的滑动
1.View本身提供的srcollTo/scrollBy方法来实现
mScrollX、mScrollY 分别代表视图内容水平方向和竖直方法的滚动距离。scrollTo和scrooBy来实现滑动,只能将View的内容进行移动,并不能将View本身进行移动。
2.使用动画
View动画、属性动画
3.改变布局参数
改变LayoutParams,右移动100px,将这个view的LayoutParams的marginLeft参数增加100px。或者在View的左边放置一个空的View,默认宽度为0,重新设置新View的宽度达到右移的效果。
View的事件分发机制
⭐⭐⭐精华总结
public boolean dispatchTouchEvent(MotionEvent ev)
用来进行事件的分发,如果事件能够传递给当前View,此方法一定会被调用,返回结果受当前View的onTouchEvent和下级的dispatchTouchEvent方法的影响,表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent event)
在上述方法内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一事件序列当中,此方法不会被在调用,返回结果表示是否拦截事件。
public boolean onTouchEvent(MotionEvent event)
dispatchTouEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。
三者的关系:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,它的dispatchTouch就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件会交给这个ViewGroup的onTouchEvent处理;如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示不拦截,事件就会继续传递给它的子元素,子元素的dispatchTouchEvent方法就调用,如此反复直到事件被最终处理。
public boolean dispatchTouchEvent(MotionEvent ev) { boolean consume = false; if(onInterceptTouchEvent(ev)) { consume = onTouchEvent(ev); } else { consume = child.dispatchTouchEvent(ev); } return consume; }
点击事件分发的传递规则:
事件由下而下的传递规则:当点击事件产生后会由Activity来处理,传递给PhoneWindow,再传递给DecorView,最后传递给顶层的ViewGroup。一般事件传递只考虑ViewGroup的onInterceptTouchEvent方法。对于根ViewGroup,点击事件首先传递给它的dispatchTouchEvent()方法,如果该ViewGroup的onInterceptTouchEvent()返回true,则表示它要拦截这个事件,这个事件就会交给它的onTouchEvent()处理;如果onInterceptTouchEvent()方法返回false,则表示它不拦截这个事件,这个事件会交给它子元素的dispatchTouchEvent()处理,如此反复下去,底层View没有子View,会调用view的dispatchTouchEvent()方法,最终调用View的onTouchEvent()方法。
事件由下而上传递:当点击事件传给底层View时,如果onTouchEvent()方法返回true,则事件由底层View消耗并处理;如果返回false则表示该View不做处理,传递给父View的onTouchEvent()处理,如果父View的onTouchEvent()仍旧返回false,则继续传递给父View的父View处理。
Scroller
Scroller本身不能实现View的滑动,需要View的computeScroll方法才能完成弹性滑动,它不断地让View重绘,每次重绘距滑动起始时间都会有一个间隔,小幅度滑动形成弹性滑动。
private void smoothScrollBy(int dx ,int dy) { mScroller.startScroll(getScrollX(),0,dx,0,500); invalidate(); }
public void computeScroll() { if(mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); postInvalidate(); } }