默认情况下事件分发会按照由Activity到ViewGroup再到View的顺序进行分发
事件的传递流程是从PhoneWindow->DecorView(mDecor是getWindow().getDecorView()返回的View,通过setContentView设置的View是该View的子View),再传递到Activity的View树。
[](
)1.View的事件分发的重要的方法:diapatchTouchEvent和touchEvent,onClick
================================================================================================================
|---View | |---boolean dispatchTouchEvent(MotionEvent event) | |--- boolean onTouchEvent(MotionEvent event)
[](
)1.1 dispatchTouchEvent: 如果事件由视图处理,则为true,否则为false。
===========================================================================================================
public boolean dispatchTouchEvent(MotionEvent event) { // If the event should be handled by accessibility focus first. if (event.isTargetAccessibilityFocus()) { // We don't have focus or no virtual descendant has it, do not handle the event. if (!isAccessibilityFocusedViewOrHost()) { return false; } // We have focus and got the event, then use normal event dispatch. event.setTargetAccessibilityFocus(false); } boolean result = false; if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(event, 0); } final int actionMasked = event.getActionMasked(); if (actionMasked == MotionEvent.ACTION_DOWN) { // Defensive cleanup for new gesture stopNestedScroll(); } if (onFilterTouchEventForSecurity(event)) { if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { result = true; } // 重点 判断listenerInfo 中是否有事件listenter 并且mOnTouchListener.onTouc 返回true ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } // 第二个重点,如果上述判断为false,并且 onTouchEventr返回为true,消耗事件 if (!result && onTouchEvent(event)) { result = true; } } if (!result && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); } // Clean up after nested scrolls if this is the end of a gesture; // also cancel it if we tried an ACTION_DOWN but we didn't want the rest // of the gesture. if (actionMasked == MotionEvent.ACTION_UP || actionMasked == MotionEvent.ACTION_CANCEL || (actionMasked == MotionEvent.ACTION_DOWN && !result)) { stopNestedScroll(); } return result; }
dispatchTouchEvent中final int actionMasked = event.getActionMasked();
ListenerInfo :将view所有的listener信息封装到一个对象中。
在该方法中有两个判断:
ListenerInfo li = mListenerInfo; if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } 复制代码
如果onTouchEvent或者是onTouchListenner是true的话,会消费此事件,同时,在这里也走了onTouchEvent
boolean onTouchEvent
MotionEvent.ACTION_UP:调用了PerformClick()
[](
)三个问题:
==============================================================
[](
)1. 在activity中调用了
==========================================================================
mTouchView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.e("TAG", "onTouch: " + event.getAction()); return false; } }); mTouchView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("TAG", "onClick: " ); } }); /***********TabLayout************/ @Override public boolean onTouchEvent(MotionEvent event) { Log.e("TAG", "onTouchEvent: "+event.getAction()); return super.onTouchEvent(event); } 复制代码
执行顺序:
[](
)2. 如果是Tablyout中直接return ture呢?
========================================================================================
不执行onClick,因为onClick在View.OntouchEvent中的ACTION_UP中,若直接return true 就不会走super中的方法。
[](
)3. 如果是dispatchEvent return true呢?
===========================================================================================
什么都不执行
[](
)分发流程
=============================================================
super.dispatchEvent->ListenerInfo->super.onTouchEvent(event)->ACTION_UP->performListener(). 复制代码
[](
)2. ViewGroup的事件分发:
============================================================================
首先是actionDown:
if (actionMasked == MotionEvent.ACTION_DOWN || 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; } }