【Android 自定义 View】事件分发机制

事件分发流程

事件手机后最先传递给 Activity,然后依次向下传递:

Activity - > PhoneWindow - > DecorView - > ViewGroup - > ... - > View

如果没有任何View消费掉事件,那么这个事件会按照反方向回传,最终传回给Activity,如果最后 Activity 也没有处理,本次事件才会被抛弃:

Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View

ViewGroup#dispatchTouchEvent

ViewGroup 的事件分发流程可以用以下伪代码来概括

public boolean dispatchTouchEvent(MotionEvent event){
    //默认事件没有被消费
    boolean result  = false;
    //如果 ViewGroup 自身没有拦截事件,事件传递给子 View
    if(!onInterceptTouchEvent){
        result = child.dispatchTouchEvent(event);
    }
    //如果 ViewGroup 拦截了事件,或者没有拦截但是子 View 并没有消费事件,调用 ViewGroup 的 onTouchEvent 方法
    if(result){
        result = onTouchEvent(event);
    }
    //将事件的消费结果返回给父 View,父 View 根据返回值来调用自身的 onTouchEvent 方法,返回 true 表示事件被消费,返回 false 表示事件没有被消费
    return result;
}

ViewGroup#onInterceptTouchEvent

ViewGroup#onInterceptTouchEvent() 方法是默认返回 false,即 ViewGroup 默认不拦截任何事件,如果想要让 ViewGroup 拦截事件,那么应该在自定义的 ViewGroup 中重写这个方法。

ViewGroup#onTouchEvent

ViewGroup 没有重写 View 的 onTouchEvent 方法。默认情况下,View 是可点击的,返回 true,不可点击返回 false。

  • onInterceptTouchEvent 方法返回 true 表示拦截事件,返回 false 表示不拦截事件,onTouchEvent 返回 true 表示消费事件,返回 false 表示不消费事件,与是否使用了触摸事件没有关系;
  • dispatchTouchEvent 方法内部调用 onInterceptTouchEvent 方法和 onTouchEvent 方法,以及子 View 的 dispatchTouchEvent 方法,返回 true 通知父 View 事件已被消费,返回 false 通知父 View 事件没有被消费,交给父 View 处理。

View#dispatchTouchEvent

可以用如下伪代码来表示 View 的事件分发过程。

public boolean diapatchTouchEvent(MotionEvent event){
    if(mOnTouchListener.onTouch(this,event)){
        return true;
    }else if(onTouchEvent(event)){
        return true;
    }
    return false;
}

在 View 的 diaptchTouchEvent 方法中如果注册了 onTouchListener ,最先调用的是 onTouchListener 的 onTouch 方法, 如果 onTouchListenr 的 onTouch 方法返回 true,则 diaptchTouchEvent 方法返回 true,不再执行 onTouchEvent 方法;如果返回 false,则调用 View 的 onTouchEvent 方法,onTouchEvent 返回 true 则dispatchTouchEvent 方法返回 true,否则返回 false。

View#onTouchEvent

在 onTouchEvent 方法里面判断 View 是否是 clickable 或 long_clickable,如果是则回调 onLongClickListener 和 onClickListener 的 onClick 方法,onTouchEvent 返回 true,无论有没有注册 onLongClickListener 和 onClickListener,只要 View 是可点击的,不对 onTouchEvent 方法进行重写,默认就会返回 true,消费事件。

  • 不论有没有注册事件,只要 View 是可点击的就会对事件进行消费,只要给 View 注册了 onClickListener、onLongClickListener、onConotextClickListener 中的任何一个监听器,View 的状态一定会变为 clickable,onTouchEvent 方法返回 true。
  • 给 View 注册 onTouchListener 监听并不会影响 View 的可点击状态,只要 onTouchListener 不返回 true,就不会消费事件。
  • 当 ACTION_DOWN 事件发生时,经过上述事件分发流程之后某一 View 消费了该事件,则后续的 ACTION_MOVE、ACTION_UP 事件都由该 View 接收。

所以我们在自定义 View 时可以重写 ViewGroup 的 onInterceptTouchEvent 或者 View 的 onTouchEvent 方法处理触摸事件。或者给 View 注册 onTouchListener 监听,如果 onTouchListener 返回 false 不会影响原来的分发流程,返回了 true 则不会再执行 onTouchEvent
,因为 ViewGroup 重写了 dispatchTouchEvent 方法,onTouchListener 不会执行。很明显如果重写了 onTouchEvent 方法,onClickListener 等监听也将不会再执行,这个时候是否消费事件也不取决于是否是可点击的了,onTouchEvent 的返回结果由自己来定义。

参考:
(Android View 事件分发机制源码详解(View篇))[http://www.jianshu.com/p/1378b334ee85]
(安卓自定义View进阶-事件分发机制原理)[http://www.gcssloop.com/customview/dispatch-touchevent-theory]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,313评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,369评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,916评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,333评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,425评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,481评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,491评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,268评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,719评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,004评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,179评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,832评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,510评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,153评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,402评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,045评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,071评论 2 352

推荐阅读更多精彩内容