后台-插件-广告管理-首页/栏目/内容广告位一(PC) |
后台-插件-广告管理-首页/栏目/内容广告位一(手机) |
- android事件类型
public boolean> public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { > @Override public boolean superDispatchTouchEvent(MotionEvent event) { return mDecor.superDispatchTouchEvent(event); }
public boolean superDispatchTouchEvent(MotionEvent evHnZDhjYKlNent) { return super.dispatchTouchEvent(event); }
mDecor是DecorView,是PhoneWindow的一个内部类,继承FrameLayout。
FrameLayout继承自ViewGroup,接下来看事件传递在ViewGroup中是如何处理的。事件传递的主要逻辑就在ViewGroup中。
接下来看ViewGroup,dispatchToucheEvent(MotionEvent ev)是如何对事件进行分发的。
public class ViewGroup { @Override public boolean dispatchTouchEvent(MotionEvent ev) { boolean handled = false; final int action = ev.getAction(); final int actionMasked = action & MotionEvent.ACTION_MASK; // Check for interception. //按下后,第一次调用时actionMasked=down,mFirstTouchtarget=null //一直按着 actionMasked=move, 如果mFirstTouchTarget!=null说明有子view处理了touch事件 final boolean intercepted; if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (!disallowIntercept) { //调用子类复写的方法 如果为true表示拦截,false表示不拦截 intercepted =>android //第一次按下时,判断view是否处理事件的标志 boolean alreadyDispatchedToNewTouchTarget = false; //如果不拦截,则进入事件分发 if (!canceled && !intercepted) { //注意,只有ACTION_DOWN时才会遍历子View if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) { final int childrenCount = mChildrenCount; if (newTouchTarget == null && childrenCount != 0) { final ArrayList<View> preorderedList = buildTouchDispatchChildList(); final View[] children = mChildren; //开始遍历子view for (int i = childrenCoupythonnt - 1; i >= 0; i--) { final View child = getAndVerifyPreorderedView( preorderedList, children, childIndex); //isTransformedTouchPointInView 通过比对坐标,来判断事件是否落在了child上, // true是,false不是 if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { ev.setTargetAccessibilityFocus(false); // 如果事件没有落在child上,则跳过此次循环,执行下一次循环 continue; } //通过遍历TouchTarget链表查找TouchTarget,如果找到了,则break跳出循环 newTouchTarget = getTouchTarget(child); if (newTouchTarget != null) { // Child is already receiving touch within its bounds. // Give it the new pointer in addition to the>public class View { public boolean dispatchTouchEvent(MotionEvent ev) { boolean result = false; ListenerInfo li = mListenerInfo; //如果view设置了mOnTouchListener,先调用mOnTouchListener.onTouch, //如果返回true,则表示消费了此事件,不在向下传递,为啥这样说?那是因为,通过他的返回值,进行了逻辑判断 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; http:// } //如果result为false,则调用View.onTouchEvent方法 if (!result && onTouchEvent(event)) { result = true; } return result; } public boolean onTouchEvent(MotionEvent event) { switch (action) { case MotionEvent.ACTION_UP: if (mPerformClick == null) { mPerformClick = new PerformClick(); } if (!post(mPerformClick)) { //调用performClick mOnClickListener.onClick()方法 performClickInternal(); } break; case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_CANCEL: break; case MotionEvent.ACTION_MOVE: break; } return false; } public boolean performClick() { final boolean result; final ListenerInfo li = mListenerInfo; if (li != null && li.mOnClickListener != null) { playSoundEffect(SoundEffectConstants.CLICK); li.mOnClickListener.onClick(this); result = true; } else { result = false; } return result; } }[!--empirenews.page--]
如果仔细看了ViewGroup和View事件分发逻辑代码。我们可以总结为以下几点。
1.ViewGroup接收到DispatchTouchEvent调用后,先调用了onInterceptTouchEvent,通过返回值进行判断是否对事件进行拦截。我们可以在代码中复写这个方法来进行事件的拦截。
2.down事件后,ViewGoup会遍历子View,找到处理Touch事件的View,并且缓存到了TouchTarget链表中,一次事件流中,只有down的时候才会进行子View的遍历。
只有做的好处提升了性能,缓存的链表中也是为了多点触摸,会有多个view响应触摸事件。
move事件时,则会从这个链表中进行遍历,通过调用dispatchTransformedTouchEvent方法进行事件的传递。
- 在dispatchTransformedTouchEvent方法中,根据child的值是否为null进入不同的分发流程。
1)如果为null说明没有子view没有响应事件,则调用父类View的dispatchTouchEvent--->onTouchEvent方法。
2)如果child值不为null。则调用child的dispatchTouchEvent方法,
此时如果child是一个ViewGoup则还是执行ViewGoup中的分发逻辑,进行递归调用。
如果child是一个View,则调用View的dispatchTouchEvent--->onTouchEvent方法。
- 在View的dispatchTouchEvent方法中:
1)listener的onTouch优先级要高于View的onTouchEvent
2)会先调用mOnTouchListener.onTouch方法,并根据返回值进行判断是否消费事件。
3)如果上面的返回值为false,则会调用View的onTouchEvent方法。
5.在View的onTouchEvent方法中UP事件时,才会调用View设置的onClickListener的监听事件。
这就是为什么了,同时给一个View设置了onTouch监听和lonClickListener监听时,当onTouch返回true无法调用onClick事件的原因。
到此这篇关于Android事件分发机制示例分析的文章就介绍到这了,更多相关Android事件分发内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!