View的基本知识
MotionEvent 和 TouchSlop
MotionEvent是手指接触屏幕后产生的一系列事件。主要包括:
- ACTION_DOWN
- ACTION_MOVE
- ACTION_UP
获取当前点击事件的坐标,getX/getY 针对当前View ,getRawX/getRawY 获取相对于屏幕的x,y坐标。
TouchSlop 最小滑动常量 ViewConfiguration.get(getContext()).getScaledTouchaSlop()
VelocityTracher 速度追踪
GestureDetector 手势检测
Scroller 弹性滑动
通过computeScroll 和scrollTo来实现弹性滑动
事件分发机制
-事件传递过程是由外向内的,及事件总是先传递给父元素,然后由父元素传递给子元素,通过requestDissallowInterceptTouchEvent,可以在子元素中干预父元素的事件分发过程,但是ACTION_DOWN事件除外。如下源码中 DOWN事件中的resetTouchState 方法中重置了标记位。
ViewGroup#dispatchTouchEvent
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
resetTouchState();
}
// Check for interception.
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
-
mFirstTouchTarget这个在子控件处理事件后会赋值为子控件。所以当子控件处理事件后,后续不会在调用onInterceptTouchEvent。反之如果ViewGroup处理了事件,那么mFirstTouchTarget就等于null,那么onInterceptTouchEvent也不会再次调用。
-
onTouchEventListener的优先级高于onClickLisener
滑动冲突
内部拦截法和外部拦截法,不管是哪种方法,父控件的Down事件一定要返回false否则子控件就玩完了。然后就是在MOVE事件中做相应的逻辑判断,在父控件中处理就直接返回true or false,在子控件处理就parent.requestDissllowInterceptTouchEvent(false);false是请求父控件拦截的意思。