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

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

带注释的代码如下: 由于事件分发这一块分支条件太多,所以必须结合情景来分析: 前提:父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,导致后续所有的事件都会被拦截。

相关推荐
ifanatic17 分钟前
[面试]-golang基础面试题总结
面试·职场和发展·golang
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
长风清留扬3 小时前
一篇文章了解何为 “大数据治理“ 理论与实践
大数据·数据库·面试·数据治理
周三有雨14 小时前
【面试题系列Vue07】Vuex是什么?使用Vuex的好处有哪些?
前端·vue.js·面试·typescript
爱米的前端小笔记14 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
好学近乎知o14 小时前
解决sql字符串
面试
我明天再来学Web渗透19 小时前
【SQL50】day 2
开发语言·数据结构·leetcode·面试
程序员奇奥20 小时前
京东面试题目分享
面试·职场和发展
理想不理想v21 小时前
【经典】webpack和vite的区别?
java·前端·javascript·vue.js·面试
沈小农学编程1 天前
【LeetCode面试150】——202快乐数
c++·python·算法·leetcode·面试·职场和发展