View工作原理(一)事件传递原理详解

转载请说明出处:一、准备知识

1、视图坐标与布局坐标的区别如下图所示:

上图是一个坐标系,这个坐标系是无边无际的。这个无边无际的坐标系即视图坐标。手机屏幕可视范围内的坐标即手机屏幕的布局坐标(坐标原点是屏幕的左上方的(0,0)位置)即A点。屏幕里面的子视图里面可视范围内的坐标即子视图的布局坐标(坐标原点是子视图的左上方的(0,0)位置)即B点。2、android中布局关系

二、例子说明事件分发过程

这里我写了一个布局文件,展示效果如上图。当我点击View1,事件的分发过程是这样的:1、ViewGroup3的dispatchTouchEvent()方法会被调用。2、ViewGroup3调用ViewGroup2的dispatchTouchEvent()方法。3、ViewGroup2调用ViewGroup1的dispatchTouchEvent()方法。4、ViewGroup1会调用View1的dispatchTouchEvent()方法。5、View1的dispatchTouchEvent()方法调用自己的onTouchEvent()方法。在onTouchEvent方法中处理点击事件。处理完了后会返回一个true给调用它的dispatchTouchEvent()方法。6、ViewGroup1的dispatchTouchEvent()方法会返回一个true值给ViewGroup2的dispatchTouchEvent()方法。这样一直将则个true值返回到ViewGroup3的dispatchTouchEvent()方法。ViewGroup3在将这个值返回给调用它的方法。这样一个事件分发过程结束。转载请说明出处:三、ViewGroup中处理消息的详细过程通过上面的列子对事件分发的过程有个大概的了解之后,我们通过ViewGroup中的dispatchTouchEvent()方法源码和View中的dispatchTouchEvent()方法及touchEvent方法源码来详细了解android是怎样处理这个过程的。ViewGroup中的dispatchTouchEvent()方法源码如下:@Overridepublic 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// interceptif (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 systemfinal 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 eventmGroupFlags &= ~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// eventsif (!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 targetmMotionTarget = 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);}

代码说明:

背着背包的路上,看过许多人,

View工作原理(一)事件传递原理详解

相关文章:

你感兴趣的文章:

标签云: