ViewGroup事件分发
来源:互联网 发布:深圳编程培训机构 编辑:程序博客网 时间:2024/05/18 19:42
ViewGroup事件分发
ViewGroup点击事件流程
ViewGroup:dispatchTouchEvent()
->ViewGroup:onInterceptTouchEvent()
- > View:dispatchTouchEvent()
- > View:onTouchEvent()
- >ViewGroup:onTouchEvent()
ViewGroup:dispatchTouchEvent()源码
- 因为代码较多,分段思考。首先看ACTION_DOWN的代码
//是否超屏幕 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) { //---------------关键点1 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; } //------------关键点2 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; //关键点3 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. } } } } }
在关键点1中我们能看到有一个字段mMotionTarget
,先判断其是否为null, 如果不为null,则将其置为空。该字段主要目的是保存消费触摸事件的View的。
在关键点2中,对disallowIntercept
和!onInterceptTouchEvent(ev)
进行了判段,如果两者有一个为true就可以向下分发。disallowIntercept
的默认为false,可以通过在子View的dispatchTouchEvent()
中调用getParent().requestDisallowInterceptTouchEvent(true)
方法修改其值。onInterceptTouchEvent()
方法在当前类中进行实现,返回false表示不拦截,返回true表示拦截。
在关键点3中,首先在之前判断了该View是否包含触摸点,其次if中判断childView的dispatchTouchEvent()
是否返回true,如果返回true,表示childView捕获了本次触摸,则将childView 赋值给mMotionTarget
,同时结束ViewGroup的disaptchTouchEvent()
方法,并返回true。
- ACTION_MOVE的代码
public boolean dispatchTouchEvent(MotionEvent ev) { 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; //...ACTION_DOWN //...ACTIN_UP or ACTION_CANCEL // The event wasn't an ACTION_DOWN, dispatch it to our target if // we have one. //-------关键点1 final View target = mMotionTarget; // if have a target, see if we're allowed to and want to intercept its // events if (!disallowIntercept && onInterceptTouchEvent(ev)) { //.... } // 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); return target.dispatchTouchEvent(ev); }
在关键点1中,直接将在ACTION_DOWN中保存的mMotionTarget
赋值给target,并return target.dispatchTouchEvent(ev);
。由此可见,之所以在childView中当ACTION_DOWN没有捕获,就无法捕获后续的ACTION_MOVE和ACTION_UP触摸,是因为此时在ViewGroup中直接将事件交给了在ACTION_DOWN中保存的处理触摸的View对象。
- ACTION_UP的代码
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) {...} boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) || (action == MotionEvent.ACTION_CANCEL); if (isUpOrCancel) { mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT; } final View target = mMotionTarget; if(target ==null ){...} if (!disallowIntercept && onInterceptTouchEvent(ev)) {...} 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); return target.dispatchTouchEvent(ev); }
在ACTION_UP实现没有太大的难点,清楚一下字段属性,调用之前保存的childView对象的分发方法。
- 当没有childView来处理触摸时
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); }
当没有触摸时,会调用父类的dispatchTouchEvent(ev)
,因为ViewGroup继承自View,那么一切就很简单了。就会调用ViewGroup本身的onTouchEvent()
。
总结
- 在ACTION_DOWN中,如果ViewGroup中有能处理该次触摸的childView,则将会调用childView的
dispatchTouchEvent
,同时保存childView对象。当本次触摸的ACTION_MOVE和ACTION_UP事件,也将有此次childView来处理。 - 当ViewGroup中没有能够处理此次触摸的childView,则会调用其父类View的
dispatchTouchEvent()
方法,那么就类似childView的调用了。
- android 事件分发 ViewGroup
- ViewGroup的事件分发
- ViewGroup事件分发机制
- ViewGroup事件分发处理
- ViewGroup事件分发
- ViewGroup事件分发
- ViewGroup事件分发
- ViewGroup的事件分发
- 事件分发(ViewGroup)
- viewGroup事件分发记录
- ViewGroup事件分发
- ViewGroup事件分发
- 事件分发机制---ViewGroup
- ViewGroup事件分发机制
- ViewGroup 事件分发
- ViewGroup的事件分发机制
- Android ViewGroup事件分发机制
- Android ViewGroup事件分发机制
- 12个不可不知的Sublime Text应用技巧和诀窍
- 写博客说明
- 线程的创建-1
- 对博弈的认知,及刷题总结
- 【Java内存】JVM 堆内存设置原理
- ViewGroup事件分发
- bzoj 3674 可持久化并查集加强版
- Swift 2.0中常见的bug (1)
- Object-C与Swift混合开发
- Reverse Words in a String
- php传递数据给javascript
- CodeForces-630 D. Hexagons!【递推】
- leetcode 169. Majority Element
- 网上发现的一个stm32的I2C比较通俗易懂的入门例程。