专栏名称: 开发者全社区
分享和推送Java/Android方向的技术和文章,让你成为这方面的大牛,让你每天都成长一点。同时,我们也会邀请BAT的大牛分享原创!
目录
相关文章推荐
郭霖  ·  2024年终总结,花开终有时 ·  5 天前  
51好读  ›  专栏  ›  开发者全社区

读Android源码之事件分发机制最全总结

开发者全社区  · 公众号  · android  · 2017-04-20 09:56

正文

本文源码来自andorid sdk 22,不同版本会有细微差别,但核心机制是一致的

一.概述

事件分发有多种类型, 本文主要介绍Touch相关的事件分发.

对于View,ViewGroup,Activity都能处理Touch事件, 它们之间处理的先后顺序和方法有所不同.

1.1 View

1.2 ViewGroup

1.3 Activity

二. 分发原理

Input系统—进程交互文章的小节[3.3]已介绍事件分发过程的前期工作. 当UI主线程收到底层上报的input事件,便会调用InputEventReceiver.dispachInputEvent方法.

2.1 DecorView.dispatchTouchEvent

[-> PhoneWindow.java ::DecorView]

此处cb是指Window的内部接口Callback. 对于Activity实现了Window.Callback接口. 故接下来调用Activity类.

2.2 Activity.dispatchTouchEvent

[-> Activity.java]

如果重写Activity的该方法,则会在分发事件之前拦截所有的触摸事件. 另外此处getWindow()返回的是Activity的mWindow成员变量, 该变量赋值过程是在Activity.attach()方法, 可知其类型为PhoneWindow.

2.2.1 Activity.onTouchEvent

[-> Activity.java]

2.3 superDispatchTouchEvent

[-> PhoneWindow.java]

PhoneWindow的最顶View是DecorView,再交由DecorView处理。而DecorView的父类的父类是ViewGroup,接着调用 ViewGroup.dispatchTouchEvent()方法。为了精简篇幅,有些中间函数调用不涉及关键逻辑,可能会直接跳过。

2.4 ViewGroup.dispatchTouchEvent

2.4.1 onFilterTouchEventForSecurity

根据隐私策略来过滤触摸事件。当返回true,表示继续分发事件;当返回flase,表示该事件应该被过滤掉,不再进行任何分发。

2.4.2 onInterceptTouchEvent

2.4.3 buildOrderedChildList

获取一个视图组的先序列表,通过虚拟的Z轴来排序。

public float getZ() {    
   return getElevation() + getTranslationZ(); }

getZ()用于获取Z轴坐标。屏幕只有x,y坐标,而Z是虚拟的,可通过setElevation(),setTranslationZ()或者setZ()方法来修改Z轴的坐标值。

2.4.4 dispatchTransformedTouchEvent

该方法是ViewGroup真正处理事件的地方,分发子View来处理事件,过滤掉不相干的pointer ids。当子视图为null时,MotionEvent将会发送给该ViewGroup。最终调用View.dispatchTouchEvent方法来分发事件。

2.4.5 addTouchTarget

private TouchTarget addTouchTarget(View child, int pointerIdBits) {
    TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
    target.next = mFirstTouchTarget;
    mFirstTouchTarget = target;    
   return target; }

调用该方法,获取了TouchTarget,同时mFirstTouchTarget不再为null。

2.5 View.dispatchTouchEvent

[-> View.java]

  1. 先由OnTouchListener的OnTouch()来处理事件,当返回True,则消费该事件,否则进入2。

  2. onTouchEvent处理事件,的那个返回True时,消费该事件。否则不会处理

2.5.1 View.onTouchEvent

三. 总结

事件分发流程图:

  1. onInterceptTouchEvent返回值true表示事件拦截, onTouch/onTouchEvent 返回值true表示事件消费。

  2. 触摸事件先交由Activity.dispatchTouchEvent。再一层层往下分发,当中间的ViewGroup都不拦截时,进入最底层的View后,开始由最底层的OnTouchEvent来处理,如果一直不消费,则最后返回到Activity.OnTouchEvent

  3. ViewGroup才有onInterceptTouchEvent拦截方法。在分发过程中,中间任何一层ViewGroup都可以直接拦截,则不再往下分发,而是交由发生拦截操作的ViewGroup的OnTouchEvent来处理。

  4. 子View可调用requestDisallowInterceptTouchEvent方法,来设置disallowIntercept=true,从而阻止父ViewGroup的onInterceptTouchEvent拦截操作。

  5. OnTouchEvent由下往上冒泡时,当中间任何一层的OnTouchEvent消费该事件,则不再往上传递,表示事件已处理。

  6. 如果View没有消费ACTION_DOWN事件,则之后的ACTION_MOVE等事件都不会再接收。

  7. 只要View.onTouchEvent是可点击或可长按,则消费该事件.

  8. onTouch优先于onTouchEvent执行,上面流程图中省略,onTouch的位置在onTouchEvent前面。当onTouch返回true,则不执行onTouchEvent,否则会执行onTouchEvent。onTouch只有View设置了OnTouchListener,且是enable的才执行该方法。

来源:http://gityuan.com/2015/09/19/android-touch/  (点击阅读原文

养成好的阅读习惯,没事多点点广告,活动下筋骨!

看完本文有收获?请分享给更多人



Java和Android架构

欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。搜索微信公众号:JANiubility。

公众号:JANiubility