View事件分发

事件分发流程

Ⅰ.当手指触摸屏幕后,底层Input drive经过一系列调用后,事件传递到了DecorView dispatchTouchEvent()->

Ⅱ.在DecorView中,通过Window内部接口Callback,事件继续传递,因为Activity实现了该接口,故事件分发到Activity的dispatchTouchEvent()->

Ⅲ.Activity获取到事件后,在dispatchTouchEvent()中先将事件分发给所在的window,实际就是PhoneWindow,window又将事件交给它的顶级view(DecorView)处理,DecorView的superDispatchTouchEvent->

Ⅳ.DecorView是FrameLayout的子类,即ViewGroup的子类,自己没有处理,所以继续将事件交由 ViewGroup处理,ViewGroup的dispatchTouchEvent()

三个角色

①Activity:

只有分发dispatchTouchEvent、消费onTouchEvent两个方法。

dispatchTouchEvent->false:无人处理,直接调用onTouchEvent()消费事件

dispatchTouchEvent->true表示自己消费

②ViewGroup:

拥有分发、拦截和消费三个方法。对于一个ViewGroup来说,点击事件产生之后,dispatchTouchEvent()会被调用。

onInterceptTouchEvent->true:表示拦截当前事件,交给ViewGroup的onTouchEvent()处理。

onInterceptTouchEvent->false:表示不拦截当前事件,这时事件就会继续传递给它的子View,接着子View的dispatchTouchEvent()会被调用。

③View:

只有分发和消费两个方法。

dispatchTouchEvent->true:表示view可以处理对应的事件。

dispatchTouchEvent->false:表示view不处理这个事件,事件会被传递给父视图。

三个核心事件

①dispatchTouchEvent():

true:表示事件被当前视图消费掉。

false:表示停止往子View传递和分发。

②onInterceptTouchEvent():

false:不拦截,继续传递给子视图。

true:拦截,自身的onTouchEvent方法进行消费。

③onTouchEvent() :

return false则不消费事件,会被传递给父视图的onTouchEvent方法进行处理。

return true 消费事件。

view的onTouchEvent,OnClickListerner和OnTouchListener的onTouch方法 三者优先级

dispatchTouchEvent(onTouchListener)->onInterceptTouchEvent(onTouchEvent)->onClickListener


①dispatchTouchEvent中先执行mOnTouchListener.onTouch(),onTouchListener的onTouch()优先级比onTouchEvent高,会先触发。

②假如onTouch方法返回false会接着触发onTouchEvent;返回true,onTouchEvent方法则不会被调用。

③onClick事件是在onTouchEvent的MotionEvent.ACTION_UP事件通过performClick() 触发的,onClickListener执行的前提是执行了onTouchEvent,且能执行MotionEvent.ACTION_UP事件。

onTouch 和onTouchEvent 的区别

onTouch方法是View的OnTouchListener接口中定义的方法。 当一个View绑定了OnTouchListener后,当有touch事件触发时,就会调用onTouch方法;onTouchEvent 处理点击事件是在dispatchTouchEvent中掉用

ACTION_CANCEL什么时候触发

①如果在父View中拦截ACTION_UP或ACTION_MOVE,在第一次父视图拦截消息的瞬间,父视图指定子视图不接受后续消息了,同时子视图会收到ACTION_CANCEL事件。
②如果触摸某个控件,但是又不是在这个控件的区域上抬起(移动到别的地方了),就会出现action_cancel。

事件先到DecorView还是先到Window

DecorView -> Activity -> PhoneWindow -> DecorView
当屏幕被触摸,事件从Native层分发Framework层的InputEventReceiver.dispachInputEvent()->ViewRootImpl.WindowInputEventReceiver.dispachInputEvent()->ViewRootImpl中的DecorView.dispatchInputEvent()->Activity.dispatchInputEvent()->window.superDispatchTouchEvent()->DecorView.superDispatchTouchEvent()->ViewGroup.superDispatchTouchEvent()

点击事件被拦截,但是想传到下面的View,如何操作

重写子类方法requestDisallowInterceptTouchEvent(true),就不会执行父类的onInterceptTouchEvent(), 将点击事件传到下面的View,剥夺了父view对除了ACTION_DOWN以外的事件的处理权。

如何解决View的事件冲突

开发中常见的事件冲突有ScrollView与RecyclerView的滑动冲突、RecyclerView内嵌同时滑动同一方向

滑动冲突的实现方法:

外部拦截法:

指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就在ACTION_MOVE中开始拦截事件,重写onInterceptTouchEvent方法,那么后续ACTION_UP也将默认交给父View处理。

内部拦截法:

即父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。

如果子View需要此事件就直接消费,否则就交由父容器进行处理,配合requestDisallowInterceptTouchEvent(false)方法。

在 ViewGroup 中的 onTouchEvent 中消费 ACTION_DOWN 事件,ACTION_UP事件是怎么传递

一个事件序列只能被一个View拦截且消耗。因为一旦一个元素拦截了此事件,那么这个事件序列内的所有事件都会直接交给它处理(即不会再调用这个View的拦截方法去询问它是否要拦截了,而是把剩余的ACTION_MOVE、ACTION_DOWN等事件直接交给它来处理)。

Activity ViewGroup和View都不消费ACTION_DOWN,那么ACTION_UP事件是怎么传递的

ACTION_DOWN:-> Activity.dispatchTouchEvent() -> ViewGroup1.dispatchTouchEvent() -> ViewGroup1.onInterceptTouchEvent() -> view1.dispatchTouchEvent() -> view1.onTouchEvent() -> ViewGroup1.onTouchEvent() -> Activity.onTouchEvent();

ACTION_MOVE > Activity.dispatchTouchEvent() -> Activity.onTouchEvent(); -> 消费

同时对父 View 和子 View 设置点击方法,优先响应哪个

先响应子view,如果先响应父view,那么子view将永远无法响应,父view要优先响应事件,必须先调用 onInterceptTouchEvent 对事件进行拦截,事件就不会再往下传递,直接交给父 view 的 onTouchEvent 处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值