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

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

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

相关推荐
wuxinyan1234 分钟前
Java面试题033:一文深入了解MySQL(5)
java·数据库·mysql·面试
笑衬人心。38 分钟前
HTTPS详解:原理 + 加解密过程 + 面试问答
java·网络协议·http·面试·https
欧阳有财1 小时前
[java八股文][Mysql面试篇]日志
java·mysql·面试
我是哪吒3 小时前
分布式微服务系统架构第155集:JavaPlus技术文档平台日更-Java线程池实现原理
后端·面试·github
红衣信3 小时前
前端与后端存储全解析:从 Cookie 到缓存策略
前端·后端·面试
前端小巷子4 小时前
跨域问题解决方案:JSONP
前端·javascript·面试
Alfred king14 小时前
面试150 生命游戏
leetcode·游戏·面试·数组
一只叫煤球的猫16 小时前
手撕@Transactional!别再问事务为什么失效了!Spring-tx源码全面解析!
后端·spring·面试
海的诗篇_18 小时前
前端开发面试题总结-原生小程序部分
前端·javascript·面试·小程序·vue·html
胡清波20 小时前
# vue 的 Diff 算法
前端·面试