安卓事件分发从流程到情景分析

话不多说,整体时间分发的流程图附上:

带注释的代码如下: 由于事件分发这一块分支条件太多,所以必须结合情景来分析: 前提:父view viewpager,可左右滑动,子view listView, 可上下滑动。

情景1:父view onInterceptTouchEvent 为false。 结果:上下滑动可以,左右滑动不可以。 原因:父view设置了onInterceptTouchEvent为false后,down事件不会被父view拦截,事件传递到子view,mFirstTouchTarget != null,所以后续的move事件是子view处理,所以上下可以,左右不可以。

情景2:onInterceptTouchEvent 为false,ListView重写 dispatchTouchEvent 返回false 结果:左右可以,上下不可以 原因:down事件传递到子view后子view返回false,mFirstTouchTarget == null所以down事件最终由父view处理,后续move事件也由父view处理

情景4:手指点击到控件上后如果move到空白处,抬起手指后click事件不会触发。 原因:在view的onTouchEvent的move事件中:

scss 复制代码
if (!pointInView(x, y, touchSlop)) {
    // Outside button
    // Remove any future long press/tap checks
    removeTapCallback();
    removeLongPressCallback();
    if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
        setPressed(false);
    }
    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
}
ini 复制代码
if (pressed) {
    mPrivateFlags |= PFLAG_PRESSED;
} else {
    mPrivateFlags &= ~PFLAG_PRESSED;
}

如果移动到view外,会将mPrivateFlags & PFLAG_PRESSED置反,所以在up事件中:

scss 复制代码
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {

条件则不会满足,导致onClick不会触发。

情景5:前提:设ViewGroup VG中,有2个Button:A,B:3. 按下A,按下VG(空白区域),为什么先释放A,却无法触发A的点击事件,继续释放VG,又会触发A的点击事件。 原因:先释放A无法触发点击事件很好理解,因为此时是point_up事件,释放空白位置会触发的原因是:

csharp 复制代码
if (newTouchTarget == null && mFirstTouchTarget != null) {
    // Did not find a child to receive the event.
    // Assign the pointer to the least recently added target.
    newTouchTarget = mFirstTouchTarget;
    while (newTouchTarget.next != null) {
        newTouchTarget = newTouchTarget.next;
    }
    newTouchTarget.pointerIdBits |= idBitsToAssign;
}

在多指操作中,如果没有view处理某个时间,则把这个事件分发给target链表中的最后一个上,这样实际上虽然第二次按在了空白处,但up时间仍然是交给A处理,所以能够触发A的点击事件

情景6:按下VG(空白区域),为什么点击A,B无响应 原因: 按下空白区域由于没有子View处理该时间,所以mFirstTouchTarget为null

java 复制代码
if (actionMasked == MotionEvent.ACTION_DOWN
        || mFirstTouchTarget != null) {
    final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    if (!disallowIntercept) {
        intercepted = onInterceptTouchEvent(ev);
        /// M : add log to help debugging
        if (intercepted == true && ViewDebugManager.DEBUG_TOUCH) {
            Log.d(TAG, "Touch event was intercepted event = " + ev
                    + ",this = " + this);
        }
        ev.setAction(action); // restore action in case it was changed
    } else {
        intercepted = false;
    }
} else {
    // There are no touch targets and this action is not an initial down
    // so this view group continues to intercept touches.
    intercepted = true;
}

这样intercepted会置为true,导致后续所有的事件都会被拦截。

相关推荐
蝎子莱莱爱打怪12 小时前
XZLL-IM干货系列 03|消息 ID 设计:一个 UUID 搞不定的事,我用两个 ID 解决了
后端·面试·开源
梯度不陡13 小时前
AI 到底能不能从零写软件?ProgramBench 和 RepoZero 给出了两种答案
前端·javascript·面试
胡萝卜术15 小时前
滑动窗口最大值:从暴力到单调队列,层层优化全解析
前端·javascript·面试
沉默王二17 小时前
面试结束后,我反问:“就面个实习至于上这么大强度吗?”面试官:“你对 RAG、Agent、MCP、Skill 理解得很到位,所以要求高一点。”
面试·agent·ai编程
假如让我当三天老蒯19 小时前
Options API(选项式 API) 和 Composition API(组合式 API)
前端·vue.js·面试
假如让我当三天老蒯2 天前
前端跨域解决方案(学习用)
前端·javascript·面试
Colin草率地做慢慢地改2 天前
关于QuickStore这个项目的重构(2)- 数据库建表文件
后端·面试·架构
JieE2122 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
JustHappy3 天前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom3 天前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github