1、当一个点击事件(MotionEvent)产生后,事件最先传递给当前的界面(Activity),这点是很好理解的。 Activity再将事件传递给窗口(Window),然后Window将事件传递给顶级View(DecorView)。此时,事件已经到达了View了。之后顶级View就会按照事件分发机制去分发事件。具体是这样的:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的 dispatchTouchEvent 方法就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGrou
2、p处理,即它的onTouchEvent方法就会被调用。如果这个ViewGroup的onInterceptTouchEvent方法返回false,就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。如果一个View的onTouchEvent方法返回false,那么它的父容器的onTouchEvent方法会被调用,如果它的父容器的onTouchEvent方法还是返回false,那就继续往上抛,当所有的元素都不处理这个事件,那么这个事件会最终传递给Activity处理,即Activity的onTou
3、chEvent方法会被调用。好了,现在已经铺垫了基础,那么接下来就从源码的角度来分析事件分发机制。当然是从Activity的dispatchTouchEvent方法开始分析。源码如下:public boolean dispatchTouchEvent(MotionEvent ev) if (ev.getAction() = MotionEvent.ACTION_DOWN) onUserInteraction(); if (getWindow().superDispatchTouchEvent(ev) return true; return onTouchEvent(ev);如果当前事件是dow
4、n的话,就调用onUserInteraction方法,onUserInteraction是一个空方法,我们可以暂时不搭理。然后调用getWindow方法获取到当前Activity关联的Window,Window再调用superDispatchTouchEvent方法将事件传入进行分发。如果superDispatchTouchEvent方法返回true的话, view已经处理了事件。整个事件循环结束。如果返回false,没有view处理这个事件。事件往上抛,那就Activity自己处理了,即Activity的onTouchEvent方法会被调用。因为想要知道事件的整个分发过程,现在关注的是Win
5、dow的superDispatchTouchEvent方法,那么就跟进去看看:public abstract boolean superDispatchTouchEvent(MotionEvent event);Window是一个抽象类,superDispatchTouchEvent是一个抽象的方法,那么我们必须要找到window的实现类才行,可是茫茫人海怎么找呢?看到window类的说明就明白了* The only existing implementation of this abstract class is * android.view.PhoneWindow, which you s
6、hould instantiate when needing a * Window. */public abstract class Window意思是Window存在唯一的实现是android.view.PhoneWindow那么PhoneWindow里的superDispatchTouchEvent方法就是我们要找的信息,如下:Overridepublic boolean superDispatchTouchEvent(MotionEvent event) return mDecor.superDispatchTouchEvent(event);直接将事件传递给了DecorView。这时事
7、件已经是到达View了哦。那么跟进DecorView的superDispatchTouchEvent方法看看,如下: return super.dispatchTouchEvent(event);内部调用了父类的dispatchTouchEvent方法,那么DecorView的父类是什么呢?DecorView肯定是View的,那么刚才开篇提到,我们通过setContentView设置的View,是DecorView的子View。那么更加准确的说DecorView是一个ViewGroup。private final class DecorView extends FrameLayout impl
8、ements RootViewSurfaceTaker可以看到DecorView是继承自FrameLayout,FrameLayout是ViewGroup,也就是说DecorView是一个ViewGroup。那么现在只需要关注ViewGroup的dispatchTouchEvent方法。继续前进ViewGroup的事件分发ViewGroup的dispatchTouchEvent方法如下: /代码省略 / Check for interception. final boolean intercepted; if (actionMasked = MotionEvent.ACTION_DOWN |
9、mFirstTouchTarget != null) final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) intercepted = onInterceptTouchEvent(ev); ev.setAction(action); / restore action in case it was changed else intercepted = false; / There are no touch targets and this ac
10、tion is not an initial down / so this view group continues to intercept touches. intercepted = true;canceled & !intercepted) final int childrenCount = mChildrenCount; if (newTouchTarget = null & childrenCount != 0) final float x = ev.getX(actionIndex); final float y = ev.getY(actionIndex); / Find a
11、child that can receive the event. / Scan children from front to back. final ArrayList preorderedList = buildOrderedChildList(); final boolean customOrder = preorderedList = null & isChildrenDrawingOrderEnabled(); final View children = mChildren; for (int i = childrenCount - 1; i i-) final int childI
12、ndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; final View child = (preorderedList = null) childrenchildIndex : preorderedList.get(childIndex); / If there is a view that has accessibility focus we want it / to get the event first and if not handled we will perform a / normal dispatc
13、h. We may do a double iteration but this is / safer given the timeframe. if (childWithAccessibilityFocus != child) continue; childWithAccessibilityFocus = null; i = childrenCount - 1;canViewReceivePointerEvents(child) | !isTransformedTouchPointInView(x, y, child, null) ev.setTargetAccessibilityFocus(false); newTouchTarget = getTouchTarget(child); if (newTouchTarget ! / Child is already receiving touch within its bounds.
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1