安卓View事件分发

本文详细解析了安卓View的事件分发流程,从ACTION_DOWN开始,依次讲解了Activity的dispatchTouchEvent,ViewGroup的dispatchTouchEvent,以及View的dispatchTransformedTouchEvent。文中提到,ACTION_DOWN时会触发onUserInteraction,并在ViewGroup中判断是否拦截事件,然后通过TouchTarget链表处理后续事件。在View中,事件会触发onTouchListener和onTouchEvent,涉及长按和短按事件的检测。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事件分发:硬件 -> ViewRootImpl -> DecorView -> PhoneWindow -> Activity - > PhoneWindow -> DecorView -> ViewGroup

到达Activity,开始分析

public boolean dispatchTouchEvent(MotionEvent ev) {

        if (ev.getAction() == MotionEvent.ACTION_DOWN) {

            onUserInteraction(); //默认是空方法,按屏幕、菜单键home键都会调用,可以做亮屏,等

        }

        if (getWindow().superDispatchTouchEvent(ev)) { //会到viewgroup里面去

            return true;

        }

        return onTouchEvent(ev);

}

1.ACTION_DOWN,onUserInteraction()

getWindow().superDispatchTouchEvent(ev)

PhoneWindow.java中的superDispatchTouchEvent()方法

mDecor.superDispatchTouchEvent(event) //mDecor就是DecorView,位于PhoneWindow内部类

DecorView继承FrameLayout,FrameLayout继承ViewGroup,所以去执行ViewGroup的dispatchTouchEvent(ev)。

2.viewGroup.dispatchTouchEvent()

1.ACTION_DOWN,resetTouchState(),重置一些参数

2.当时ACTION_DOWN时,intercepted = onInterceptTouchEvent(),一个touch事件只执行一次

如果intercepted=true,表示ViewGroup拦截此事件。

然后if (mFirstTouchTarget == null) { dispatchTransformedTouchEvent()}

此时mFirstTouchTarget一定是null(因为前面reset时将其置null了,上面一段过程没人给他赋值),

直接执行dispatchTransformedTouchEvent(),其中传的chile是空,然后直接调super.dispatchTouchEvent(event),就把自己当做一个view处理事件了。

3.如果intercepted=false,并且是ACTION_DOWN或者ACTION_POINTER_DOWN或者ACTION_HOVER_MOVE,

// ACTION_POINTER_DOWN非第一个点被按下

才去执行for循环里面,先canViewReceivePointerEvents()看能不能点击,不能则直接continue下一个。

判断isTransformedTouchPointInView()是否在该子View内,如果不在则直接continue下一个。

然后newTouchTarget = getTouchTarget(child);看child是不是在mFirstTouchTarget为首的链表里面。

此时不在。

如果在的话,直接break跳出循环。如果不在的话,对child做dispatchTransformedTouchEvent()。

4.如果该dispatchTransformedTouchEvent()返回true,说明事件被这个child消费了。

然后执行newTouchTarget = addTouchTarget(child, idBitsToAssign)将child构建TouchTarget,然后放到TouchTarget链表里面。插到链表的第一位。mFirstTouchTarget指向第一个target元素。

然后alreadyDispatchedToNewTouchTarget = true;接着break,跳出循环。

3和4是在action_down执行的,所以后面的action_up直接就走第5步。

寻找处理事件的child只执行一次,只有在action_down执行,后面actionUP从链表直接处理。

 

如果是actionUP,直接if (mFirstTouchTarget == null) (跟第二步那个相同位置),然后while循环查找mFirstTouchTarget,找到那个actiondown处理的target,直接调用此child的dispatchTransformedTouchEvent处理事件。

 

5.然后mFirstTouchTarget不是null,进入while循环,

当alreadyDispatchedToNewTouchTarget为true,handled=true,然后返回handled,

就是dispatchTouchEvent()返回值。

 

下一次touch_up事件来的时候,直接intercepted=false,执行第3步。

3.View.dispatchTransformedTouchEvent()

dispatchTransformedTouchEvent()里面,判断child是不是空,如果不是,调用child.dispatchTouchEvent(event)

如果child是view,直接执行View.dispatchTransformedTouchEvent(),否则执行viewgroup的。

1.先执行mOnTouchListener.onTouch()方法,回调onTouch()

2.如果onTouch()返回false,才去执行onTouchEvent()

3.在onTouchEvent()里面,在ACTION_DOWN时,发一个mPendingCheckForTap的runable去异步执行里面的checkForLongClick()方法检测是不是长按事件。(此处post延迟500ms)

4.checkForLongClick()里面发一个mPendingCheckForLongPress的runable去执行performLongClick()事件,执行完毕之后,将mHasPerformedLongPress = true。(此处post延迟500-100=400ms)

(如果是短按事件,在ACTION_UP时,判断mHasPerformedLongPress =false,

然后removeCallbacks(mPendingCheckForLongPress);此时不会执行长按事件的。)

5.在ACTION_UP时,判断mHasPerformedLongPress =false,然后removeCallbacks(mPendingCheckForLongPress);此时不会执行长按事件的。

然后执行performClick(),回调onClick()事件。

 

checkForLongClick()第一次执行延迟500ms,第二次执行延迟500-100=400ms,差不多是900ms。

注:onTouchEvent里面有判断CLICKABLE,action_up里面会有performClick执行onclick事件。

 

结论:

1. onTouch和onTouchEvent有什么区别,又该如何使用?

两个方法都是在View的dispatchTouchEvent中调用的,onTouch优先于onTouchEvent执行。如果在onTouch方法中通过返回true将事件消费掉,onTouchEvent将不会再执行。

onTouch能够得到执行需要两个前提条件,第一mOnTouchListener的值不能为空,第二当前点击的控件必须是enable的。

 

因此如果你有一个控件是非enable的:imageView3.setEnabled(false);

那么给它注册onTouch事件将永远得不到执行。

对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值