在我们使用手机的时候,会与应用进行各种交互行为,每次滑动,点击都是一种触摸事件,在Android中有如下一些触摸事件
- ACTION_DOWN = 0,手触摸到屏幕时触发
- ACTION_UP = 1,手按完屏幕,离开屏幕时出发
- ACTION_MOVE = 2,手在屏幕上滑动时触发
- ACTION_CANCEL =3,接收到触摸事件中任一事件后,其后续的事件被拦截无法接收,则触发cancel
- ACTION_OUTSIDE = 4,手滑到屏幕外或者View之外,一般不由该View进行处理,而是通过Window.Callback进行回调
如何分发触摸事件
大致分发流程
Activity收到事件,并传给小弟处理(DecorView也是一个ViewGroup)
Activity -> PhoneWindow -> ViewGroup -> ... -> View
若小弟处理不了,则回传给Activity
Activity <- PhoneWindow <- ViewGroup <- ... <- View
对于事件,Android中有三个方法来处理它
- dispatchTouchEvent() -- 分发事件,将事件传递出去
- onInterceptTouchEvent() -- 拦截事件,子View或下一层级的就收不到该事件
- onTouchEvent() -- 处理事件
Activity,ViewGroup,View中是否含有上述方法
方法 | Activty | ViewGroup | View |
---|---|---|---|
dispatchTouchEvent() | √ | √ | √ |
onInterceptTouchEvent() | × | √ | × |
onTouchEvent() | √ | √ | √ |
由上表可见,Activity和View都没有拦截事件的方法
因为Activiy处于事件分发的顶端,若拦截了,View就无法做出响应,影响用户体验
而View处于最底层,再拦截事件已经没有意义,要么就处理掉事件,要么就不做处理
分发流程的比喻
- Activity:老板
- RootView:经理
- ChildView:员工
在方法中进行打印log,默认调用父类方法(即返回值均为false),布局如下
Tips:操作方式为点击ChildView,只有Down,没有Up的行为,模拟器上鼠标按住即可
dispatchTouchEvent: ---------ViewActivity--老板:接到活啦
dispatchTouchEvent: ---------RootView-----经理:我也接到活啦
onInterceptTouchEvent: -----RootView-----经理:偷懒,丢给员工做
dispatchTouchEvent: ---------ChildView----员工:狗经理又来压榨我了,收到任务
onTouchEvent: -----------------ChildView----员工:发现做不了,告知经理
onTouchEvent: -----------------RootView----经理:报告老板,做不了啊!
onTouchEvent: -----------------ViewActivity-老板:报告客户,这活我不做了
ChildView中onTouchEvent为true时,即员工发现这个活自己能做,则经理和老板就不用处理啦
dispatchTouchEvent: ---------ViewActivity
dispatchTouchEvent: ---------RootView
onInterceptTouchEvent: -----RootView
dispatchTouchEvent: ---------ChildView
onTouchEvent: -----------------ChildView
RootView中onInterceptTouchEvent为true时,经理有B数,知道员工做不了,就不告知员工了,此时员工不需要处理,只要经理上报回老板即可
dispatchTouchEvent: -------ViewActivity
dispatchTouchEvent: -------RootView
onInterceptTouchEvent: ---RootView
onTouchEvent: ---------------RootView
onTouchEvent: ---------------ViewActivity
总结
对于 dispatchTouchEvent
- Activity
- ture:事件被消耗,不会传递给经理,就是不理会客户的活
- false:接活,并传下去让下一层处理
- ViewGroup(RootView)
- 情况跟Activity类似,要么不做,要么传给小弟
- View
- true:回调onTouchEvent()
- false:不回调
简而言之就是true时会回调onTouchEvent(),false则不回调
对于 onInterceptTouchEvent
拦截后(返回值为true),下一层不会回调dispatchTouchEvent(),而是自己处理,更不会回调下一层的onTouchEvent()
对于 onTouchEvent
false的话就会告知上层,让上层进行处理
而true的话,自己做完后就行,不必汇报上层