Android 事件分发keyEvent、touchEvent(touchListener 、touchDelegate)、hoverEvent

电视遥控器,走key事件:

dispatchKeyEventPreIme、dispatchKeyEvent、onKeyDown、view.onKeyListener、view.onClickListener

> 对于key事件来说只有两个action:KeyEvent.ACTION_DOWN和KeyEvent.ACTION_UP

> Activity的dispatchKeyEvent 作为一切事件的入口。

    public boolean dispatchKeyEvent(KeyEvent event) {
        onUserInteraction();
        Window win = getWindow();
        if (win.superDispatchKeyEvent(event)) {
            return true;
        }
        View decor = mDecor;
        if (decor == null) decor = win.getDecorView();
        return event.dispatch(this, decor != null
                ? decor.getKeyDispatcherState() : null, this);
    }

 上面是Activity中的源码。上面的代码说如果window自己消费了事件,那么return true。通常我们也不能把系统的window类改成这样。

那么就会将事件分发给decorView。(activity的decorView下的android.id.content就是咱们自己的layout的上层,是一个FrameLayout。)

> 在Activity的dispatchKeyEvent 消费某一事件(即return true)后,那onKeyDown则接收不到该事件

不消费则 return super.dispatchKeyEvent(event);  (通常重写事件时,会有默认的返回方式,

一般直接写最后,需要特殊处理并消费的地方才return true)

> 在View中:onKeyPreIme、onKeyDown、onKeyLongPress、onKeyUp、onKeyMultiple、onKeyShortcut(不清楚作嘛的)

还有dispatchKeyEventPreIme、dispatchKeyEvent

> 在ViewGroup中:dispatchKeyEventPreIme、dispatchKeyEvent

> dispatchKeyEventPreIme(在键盘Ime接收前执行)  会比 dispatchKeyEvent先执行,

一般如果没有键盘输入的界面,重写任意一个都可以

> onClick:在一个完整的action_down和action_up周期后,才会执行onClick

> onKeyDown、onKeyListener 基本是一样的,只是看使用时候的范围,是要监听Activity,

还是某一Layout,还是某一个View

总结:dispatch的会先执行,再到onKey;从Activity>ViewGroup(各式Layout)>view;  从action_down>action_up。

一个action_down,从activity的dispatch 往下分发,到viewGroup的dispatch。

dispatch中return true,事件不再向后传

手机,走touch事件:

跟key类似,也是从Activity的dispatchTouchEvent开始。

每个组件含有的相关方法:

  Activity : dispatchTouchEvent、onTouchEvent

  ViewGroup : dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

  View : dispatchTouchEvent、onTouchEvent

示例1:

> 下面的log,含有move动作,都返回false时(注意返回false,最好调用super.对应方法,否则可能事件不会传递):

stone-activity--dispatchTouchEvent--down--false
stone-viewGroup--dispatchTouchEvent--down--false
stone-viewGroup--onInterceptTouchEvent--down--false
stone-view--dispatchTouchEvent--down--false
stone-view--onTouchEvent--down--false
stone-viewGroup--onTouchEvent--down--false
stone-activity--onTouchEvent--down--false
stone-activity--dispatchTouchEvent--move--false
stone-activity--onTouchEvent--move--false
stone-activity--dispatchTouchEvent--up--false
stone-activity--onTouchEvent--up--false

down 事件:

自顶向下:activity(dispatch) -> viewGroup(dispatch, onIntercept) -> View (dispatch); 

自底向上:view (onTouch) -> viewGroup(onTouch) -> activity(onTouch)

viewGroup 和 view 没有对 down 事件 进行消费(即返回 true)。就收不到后续的 move、up 事件。只有 activity 来处理 move、up 事件。

示例2:

> 下面的log, 在activity--dispatchTouchEvent—down, 返回true时,

stone-activity--dispatchTouchEvent--down--true
stone-activity--dispatchTouchEvent--move--false
stone-activity--onTouchEvent--move--false
stone-activity--dispatchTouchEvent--up--false
stone-activity--onTouchEvent--up--false

activity 的 dispatch 中的 down 事件被消费,造成了后续链的断开。

示例3:

> 下面的log,在viewGroup—dispatchTouchEvent—down,返回true时,

stone-activity--dispatchTouchEvent--down--false
stone-viewGroup--dispatchTouchEvent--down--true
stone-activity--dispatchTouchEvent--move--false
stone-viewGroup--dispatchTouchEvent--move--false
stone-viewGroup--onTouchEvent--move--false
stone-activity--onTouchEvent--move--false
stone-activity--dispatchTouchEvent--up--false
stone-viewGroup--dispatchTouchEvent--up--false
stone-viewGroup--onTouchEvent--up--false
stone-activity--onTouchEvent--up--false

与示例1相比,在viewGroup—dispatchTouchEvent—down 被消费了,那其后的 down 事件就不传递了。

示例4:

> 下面的log,在viewGroup--onInterceptTouchEvent—down,返回true时,

stone-activity--dispatchTouchEvent--down--false
stone-viewGroup--dispatchTouchEvent--down--false
stone-viewGroup--onInterceptTouchEvent--down--true
stone-viewGroup--onTouchEvent--down--false
stone-activity--onTouchEvent--down--false
stone-activity--dispatchTouchEvent--move--false
stone-activity--onTouchEvent--move--false
stone-activity--onTouchEvent--move--false
stone-activity--dispatchTouchEvent--up--false
stone-activity--onTouchEvent--up--false

拦截后,直接执行 viewGroup 的 onTouchEvent(down)

> 下面的log,在view--dispatchTouchEvent—down,返回true时,

stone-activity--dispatchTouchEvent--down--false
stone-viewGroup--dispatchTouchEvent--down--false
stone-viewGroup--onInterceptTouchEvent--down--false
stone-view--dispatchTouchEvent--down--true
stone-activity--dispatchTouchEvent--move--false
stone-viewGroup--dispatchTouchEvent--move--false
stone-viewGroup--onInterceptTouchEvent--move--false
stone-view--dispatchTouchEvent--move--false
stone-view--onTouchEvent--move--false
stone-activity--dispatchTouchEvent--up--false
tone-viewGroup--dispatchTouchEvent--up--false
stone-viewGroup--onInterceptTouchEvent--up--false
stone-view--dispatchTouchEvent--up--false
stone-view--onTouchEvent--up--false
stone-activity--onTouchEvent--up--false


结合上面的示例log,总结:

> 组件传递顺序:Activity、ViewGroup、View

> 事件传递顺序:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent

> 默认传递顺序:

dispatchTouchEvent-down从上到下(如果经过ViewGroup,还会经过onInterceptTouchEvent-down);

直至传递到View级的onTouchEvent,onTouchEvent 再从下到上传递,即View、ViewGroup、Activity;

若down事件没有任何地方拦截,后续的move、up只发生在Activity

> 在Activity、ViewGroup、View的 dispatchTouchEvent-down 时,返回true:表示消费掉该down事件,down事件不会再传递;

且后续的move、up事件,会经过当前组件的dispatchTouchEvent和onTouchEvent

> 再说一些:

a. dispatchTouchEvent 某一级组件的action事件,返回true,就会消费掉该action事件,不继续传递它,

且后续action会经过当前组件的dispatchTouchEvent和onTouchEvent

b. 如果想执行到ViewGroup或ViewonTouchEvent-action(move|up),

那么要在该组件的dispatchTouchEvent-down或onTouchEvent-down时,需要返回true

c. ViewGroup的onInterceptTouchEvent,若某个action事件返回true,则也不会向子view传递,

但会转发事件到当前ViewGroup的onTouchEvent

注:

> View#onTouchEvent 默认会返回 true,即消费事件;除非它是不可点击的(clickable 和 longClickable 同为 false)

View的 dispatchTouchEvent 中,会判断是否有 OnTouchListener,有就先执行,且OnTouchListener消费了事件,则 onTouchEvent就不再执行。

在 up 后,还会判断是否有OnClickListener,若有则执行。可见它们的优先级:OnTouchListener > onTouchEvent > OnClickListener。

> 还有个特殊方法:ViewGroup#requestDisallowInterceptTouchEvent(boolean disallowIntercept),true 时用于请求父级容器,不拦截除了 down 事件之外的事件;false 继续父级拦截

ViewGroup 的 down 事件,会重置该方法对应的标记值。

>  View#onTouchEvent中,在执行 down、move、up 事件之前,会先判断是否有 TouchDelegate,若执行TouchDelegate#onTouchEvent();

且当该方法返回 true,则View#onTouchEvent不再执行。

TouchDelegate的构造方法只有一个:public TouchDelegate(Rect bounds, View delegateView);

   bounds:包含delegateView在内的 Rect;

   delegateView:负责touch 事件的委托 view;

即 当touch事件在bounds范围内,则委托给delegateView来处理

View#setTouchDelegate(TouchDelegate delegate); 用于设置

鼠标,走hover事件:

在Activity中,并没有 dispatchHoverEvent和onHoverEvent,  其它与touch类似

在ViewGroup中多一个 onInterceptHoverEvent  鼠标有三种动作

> ACTION_HOVER_ENTER 指针悬浮在view上

> ACTION_HOVER_MOVE  指针在view上移动

> ACTION_HOVER_EXIT   指针离开view边界

鼠标目前没调试过,分发原理基本类似touch

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值