View.dispatchTouchEvent()只能消费事件
ViewGroup.dispatchTouchEvent()才能分发事件
总结:事件都是从ACTION_DOWN开始的,Activity的dispatchTouchEvent()首先接收到ACTION_DOWN,执行super.dispatchTouchEvent(ev),事件向下分发。相当于ACTION_DOWN导致了决定了分发谁来处理这个事件;之后ACTION_MOVE也从Activity开始,一步一步往下走到ACTION_DOWN决定的事件,开始处理事件冲突;在这个过程中上层随时可以拦截下层的行动
https://blog.csdn.net/xyz_lmn/article/details/12517911
1.⾃定义单 View 的触摸反馈
做法:重写 onTouchEvent(),在⽅法内部定制触摸反馈算法
- 1.是否消费事件取决于 ACTION_DOWN 事件是否返回 true
若最顶部的View已被消费,则它底层的View无论是否被消费都没有作用了 - 2.多点触控应选择getActionMasked() 而不是 getAction()
- 3.POINTER_DOWN / POINTER_UP:多点触控时的事件。表示非第一根手指按下/抬起
2.View.onTouchEvent() 的源码逻辑(主要处理了点击、长按、右键点击)
1.当⽤户按下(ACTION_DOWN):
-
1.1如果不在滑动控件中,切换⾄按下状态,并注册⻓按计时器
-
1.2如果在滑动控件中,切换⾄预按下状态,并注册按下计时器
-
1.3在非滑动的自定义Layout中应重写,来防止点击延迟
-
2.当进⼊按下状态并移动(ACTION_MOVE):
- 2.1重绘 Ripple Effect
- 2.2如果移动出⾃⼰的范围,⾃我标记本次事件失效,忽略后续事件
3.当⽤户抬起切换⾄抬起状态(ACTION_UP),并清除⼀切状态:
- 3.1如果是按下状态并且未触发⻓按,切换⾄抬起状态并触发点击事件,并清除
⼀切状态 - 3.2如果已经触发⻓按,切换⾄抬起状态并清除⼀切状态
4.当事件意外结束(ACTION_CANCEL):
切换⾄抬起状态(ACTION_MOVE),并清除⼀切状态
3.⾃定义 ViewGroup 的触摸反馈
所以当父ViewGroup需要消费事件的时候需要重写以下两个方法
- Activity.dispatchTouchEvent()
- 递归: ViewGroup(View).dispatchTouchEvent()
ViewGroup.onInterceptTouchEvent()
child.dispatchTouchEvent()
super.dispatchTouchEvent()
- View.onTouchEvent() - Activity.onTouchEvent()
- 递归: ViewGroup(View).dispatchTouchEvent()