Android 触摸消息派发之ViewGroup的派发过程
来源:互联网 发布:数据库实训报告 编辑:程序博客网 时间:2024/09/21 09:22
Android系统中一个完整的触摸消息过程为ACTION_DOWN,然后是ACTION_MOVE,最后是ACTION_UP。整个过程中涉及的函数有dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。
当触摸消息派发到ViewGroup时会调用dispatchTouchEvent方法,它负责整个触摸消息的处理。在dispatchTouchEvent方法中首先获取触摸消息的类型以及触摸点的位置,如果消息类型为ACTION_DOWN时,首先判断mMotionTarget是否为空,mMotionTarget保存的是上次触摸消息的处理者,一般在ACTION_DOWN情况下mMotionTarget为null,原因将会在后面看到,至于在ACTION_DOWN情况下mMotionTarget不为null,我也不太清楚啊(嘿嘿)。
然后是判断是否允许拦截消息或是拦截过程中是否消耗了这个消息,if判断成立的条件一是ViewGroup被设置不允许拦截触摸消息,方法是通过调用requestDisallowInterceptTouchEvent(boolean disallowIntercept),另一种情况是onInterceptTouchEvent返回false,在ViewGroup中该方法的默认实现为return false。当if条件成立时,从ViewGroup中包含的所有子View中判断该触摸消息的位置落在哪个View中,然后调用该View的dispatchTouchEvent将消息传递下去。如果子View消耗了该消息则将该View赋值给mMotionTarget变量,记录消息的处理者以便在后续的触摸消息中使用,最后函数返回true一次消息派发结束,后续的消息为ACTION_MOVE或ACTION_UP。如果子View没有消耗该消息则代码接着往下执行,代码第71行判断mMotionTarget是否为null,如果为null的话说明在ACTION_DOWN的情况下没有子View消耗该消息,所以触摸消息由ViewGroup本身处理,super.dispatchTouchEvent即调用View的dispatchTouchEvent处理。所以当触摸消息为ACTON_DOWN时可能从两个地方返回,一是代码第49行返回,另一个是从代码第80行返回。
如果消息类型为ACTION_UP或是ACTION_CANCEL,从代码85行开始首先判断在允许拦截消息并且onInterceptTouchEvent返回true的情况下表明ViewGroup本身把消息消耗了,所以就没有子View什么事了,所以后面将MotionEvent设置为ACTION_CANCEL类型,调用原来mMotionTarget的dispatchTouchEvent方法通知它触摸取消,以供子View取消长按监听等处理。然后将mMotionTarget设置为null,同时返回true,这样从ACTION_DOWN到ACTION_CANEL或ACTION_UP一个完整的触摸过程就结束了。
但是如果代码第85行ViewGroup本身没有消耗该消息,则直接调用mMotionTarget的dispatchTouchEvent方法将消息传递下去。如果mMotionTarget为ViewGroup类型则递归这个过程,如果mMotionTarget为View类型则
ViewGroup中dispatchTouchEvent函数执行过程
public boolean dispatchTouchEvent(MotionEvent ev) { if (!onFilterTouchEventForSecurity(ev)) { return false; } final int action = ev.getAction(); final float xf = ev.getX(); final float yf = ev.getY(); final float scrolledXFloat = xf + mScrollX; final float scrolledYFloat = yf + mScrollY; final Rect frame = mTempRect; boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; if (action == MotionEvent.ACTION_DOWN) { if (mMotionTarget != null) { // this is weird, we got a pen down, but we thought it was // already down! // XXX: We should probably send an ACTION_UP to the current // target. mMotionTarget = null; } // If we're disallowing intercept or if we're allowing and we didn't // intercept if (disallowIntercept || !onInterceptTouchEvent(ev)) { // reset this event's action (just to protect ourselves) ev.setAction(MotionEvent.ACTION_DOWN); // We know we want to dispatch the event down, find a child // who can handle it, start with the front-most child. final int scrolledXInt = (int) scrolledXFloat; final int scrolledYInt = (int) scrolledYFloat; final View[] children = mChildren; final int count = mChildrenCount; for (int i = count - 1; i >= 0; i--) { final View child = children[i]; if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { child.getHitRect(frame); if (frame.contains(scrolledXInt, scrolledYInt)) { // offset the event to the view's coordinate system final float xc = scrolledXFloat - child.mLeft; final float yc = scrolledYFloat - child.mTop; ev.setLocation(xc, yc); child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; if (child.dispatchTouchEvent(ev)) { // Event handled, we have a target now. mMotionTarget = child; return true; } // The event didn't get handled, try the next view. // Don't reset the event's location, it's not // necessary here. } } } } } boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL); if (isUpOrCancel) { // Note, we've already copied the previous state to our local // variable, so this takes effect on the next event mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } // The event wasn't an ACTION_DOWN, dispatch it to our target if // we have one. final View target = mMotionTarget; if (target == null) { // We don't have a target, this means we're handling the // event as a regular view. ev.setLocation(xf, yf); if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) { ev.setAction(MotionEvent.ACTION_CANCEL); mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; } return super.dispatchTouchEvent(ev); } // if have a target, see if we're allowed to and want to intercept its // events if (!disallowIntercept && onInterceptTouchEvent(ev)) { final float xc = scrolledXFloat - (float) target.mLeft; final float yc = scrolledYFloat - (float) target.mTop; mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; ev.setAction(MotionEvent.ACTION_CANCEL); ev.setLocation(xc, yc); if (!target.dispatchTouchEvent(ev)) { // target didn't handle ACTION_CANCEL. not much we can do // but they should have. } // clear the target mMotionTarget = null; // Don't dispatch this event to our own view, because we already // saw it when intercepting; we just want to give the following // event to the normal onTouchEvent(). return true; } if (isUpOrCancel) { mMotionTarget = null; } // finally offset the event to the target's coordinate system and // dispatch the event. final float xc = scrolledXFloat - (float) target.mLeft; final float yc = scrolledYFloat - (float) target.mTop; ev.setLocation(xc, yc); if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) { ev.setAction(MotionEvent.ACTION_CANCEL); target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; mMotionTarget = null; } return target.dispatchTouchEvent(ev); }
- Android 触摸消息派发之ViewGroup的派发过程
- android触摸消息的派发过程
- Android 自定义View 之 触摸消息派发
- ViewGroup中的触摸消息派发dispatchTouchEvent
- Android触摸事件派发机制源码分析之ViewGroup
- View工作原理之触摸消息派发过程
- 触摸消息的整体派发流程
- android 学习之触摸事件 -- 事件派发
- Android中按键消息的派发过程及源码分析
- Android中按键消息的派发过程及源码分析
- Android中按键消息的派发过程及源码分析
- Android中按键消息的派发过程及源码分析
- Handler的消息派发
- Android View系统源码分析(三)—— 根View内部消息派发过程&ViewGroup.dispatchTouchEvent()
- Android触摸事件派发机制源码分析之View
- Android触摸事件派发机制源码分析之Activity
- View工作原理【触摸消息派发】
- View工作原理之按键消息派发过程
- linux中 probe函数的何时调用的?
- 适配器和桥接模式小辨析
- The specified JTAG device (in the Target Connection tab) is invalid. Use the Run|Run... or Run|Debug
- java字符串格式化
- 2015.1.25实验室日志
- Android 触摸消息派发之ViewGroup的派发过程
- 工作日志
- solr-4.10.3 安装在windows7
- Android 4.4(KitKat)中的设计模式-Graphics子系统
- uva10755 - Garbage Heap (最大子立方体)
- OpenCV+kinect1.0手语识别(一) 环境配置+彩色流深度流骨架流的处理
- iOS开发-webView加载网页,加载静态HTML文件
- Spring中注解分析@component
- C# WPF Application.Current.Properties["Administrator"]; 类似Session的功能。