Android事件分发机制(二)

Android——View的事件体系(二)View的事件分发机制 主要介绍内容: View的事件分发机制 点击事件的传递规则 事件分发的源码解析 View的滑动冲突 常见的滑动冲突场景 滑动冲突的处理规则 滑动冲突的解决方式 在上一章中我们已经介绍了 View 的基础知识以及 View 的滑动,想了解的请戳 Android——View的事件体系(一)View的滑动 这里本节将介绍 View 的一个核心知识点:事件分发机制。在真正进入详细探讨之前,大家 阅读详情

ViewGroup事件分发原理

首先我们先自定义一个ViewGroup的子类。

public class MyRelativeLayout extends RelativeLayout {

    public MyRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("ricky", "dispatchTouchEvent:action--"+ev.getAction()+"---view:MyRelativeLayout");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("ricky", "onInterceptTouchEvent:action--"+ev.getAction()+"---view:MyRelativeLayout");
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("ricky", "onTouchEvent:action--"+event.getAction()+"---view:MyRelativeLayout");
        return true;
    }


}

我们打印下执行顺序:

06-19 14:51:18.962 8602-8602/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0---view:MyRelativeLayout
06-19 14:51:18.962 8602-8602/com.example.shijiantest I/ricky: onInterceptTouchEvent:action--0---view:MyRelativeLayout
06-19 14:51:18.962 8602-8602/com.example.shijiantest I/ricky: dispatchTouchEvent:action--0---view:MyButton
06-19 14:51:18.962 8602-8602/com.example.shijiantest I/ricky: OnTouchListener:acton--0----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ........ 0,0-264,144 #7f070022 app:id/button}
06-19 14:51:18.962 8602-8602/com.example.shijiantest I/ricky: onTouchEvent:action--0---view:MyButton
06-19 14:51:19.042 8602-8602/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1---view:MyRelativeLayout
06-19 14:51:19.042 8602-8602/com.example.shijiantest I/ricky: onInterceptTouchEvent:action--1---view:MyRelativeLayout
06-19 14:51:19.042 8602-8602/com.example.shijiantest I/ricky: dispatchTouchEvent:action--1---view:MyButton
06-19 14:51:19.042 8602-8602/com.example.shijiantest I/ricky: OnTouchListener:acton--1----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}
06-19 14:51:19.042 8602-8602/com.example.shijiantest I/ricky: onTouchEvent:action--1---view:MyButton
06-19 14:51:19.044 8602-8602/com.example.shijiantest I/ricky: OnClickListener----view:com.example.shijiantest.MyButton{52ca23d VFED..C.. ...P.... 0,0-264,144 #7f070022 app:id/button}

 总结:dispatchTouchEvent-->onInterceptTouchEvent----->onTouchListener---return false-->onTouchEvent

我们发现跟View的基本差不多。下面我们就猜想一下,父布局是怎么对事件进行拦截的呢?我们带着猜想去看下源码:

首先我们分析下onInterceptTouchEvent:action返回true,也就是我们理解的拦截是的源码是怎样的,以及为什么返回true会执行拦截操作。我们先看下intercepted的返回情况与什么因素有关。

final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
    || mFirstTouchTarget != null) {
        final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
        if (!disallowIntercept) {
            intercepted = onInterceptTouchEvent(ev);//调用拦截方法判断
            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;
}

 public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
                && ev.getAction() == MotionEvent.ACTION_DOWN
                && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
                && isOnScrollbarThumb(ev.getX(), ev.getY())) {
            return true;
        }
        return false;
  }

我们可以发现这个返回值默认返回的是个false,也就是不进行拦截操作。我们反着进行推理,看看默认情况下我怎么执行我们顺着源码往下看。

if (!canceled && !intercepted) {
    ...

   if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
       // Child wants to receive touch within its bounds.
       mLastTouchDownTime = ev.getDownTime();
       if (preorderedList != null) {
           // childIndex points into presorted list, find original index
           for (int j = 0; j < childrenCount; j++) {
               if (children[childIndex] == mChildren[j]) {
                     mLastTouchDownIndex = j;
                     break;
               }
           }
       } else {
           mLastTouchDownIndex = childIndex;
       }
       mLastTouchDownX = ev.getX();
       mLastTouchDownY = ev.getY();
       newTouchTarget = addTouchTarget(child, idBitsToAssign);
       alreadyDispatchedToNewTouchTarget = true;
       break;
   }
    ...
} 

 private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
        final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
        target.next = mFirstTouchTarget;
        mFirstTouchTarget = target;
        return target;
    }

我们在其中mFirstTouchTarget被赋值啦,这个使我们寻找的关键。现在我们头看一下,如果intercepted返回true,那么就不会走上面的方法,也就是mFirstTouchTarget会返回一个false。

那么我们看下下面源码:

// Dispatch to touch targets.
            if (mFirstTouchTarget == null) {
                // No touch targets so treat this as an ordinary view.
                handled = dispatchTransformedTouchEvent(ev, canceled, null,
                        TouchTarget.ALL_POINTER_IDS);
            } 

private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
            View child, int desiredPointerIdBits) {
        final boolean handled;

        // Canceling motions is a special case.  We don't need to perform any                 transformations    
        // or filtering.  The important part is the action, not the contents.
        final int oldAction = event.getAction();
        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
            event.setAction(MotionEvent.ACTION_CANCEL);
            if (child == null) {
                handled = super.dispatchTouchEvent(event);
            } else {
                handled = child.dispatchTouchEvent(event);
            }
            event.setAction(oldAction);
            return handled;
        }
    ...
}

我们可以发现会执行super.dispatchTouchEvent(event),也就是执行了View的dispatchTouchEvent事件啦。不会在进行向下传递执行了。

我总结了一幅流程图

当view的onTouch返回false是其实差不多的流程:

会依次向上返回直到上层ViewGroup的onTouch去消耗这个事件。

感觉这块的源码很难分析吧,自己总结的也不是那么好,以后继续补充。



 

Android源码分析——ViewGroup的事件分发机制(二) 通过前一篇博客View的事件分发机制,从dispatchTouchEvent说起(一)的介绍相信大家对 Android View 事件的分发机制有了很深的理解。我们知道 Android 中 View 是存在于 Activity。 今天我们继续学习 Activity 到 ViewGroup 的事件分发机制。 一、Activity 分发到 ViewGroup 当我们手指触摸到屏幕时,最先接收到事件的... 阅读详情

相关推荐

安卓基础知识之View篇(二):View 事件分发机制备忘录

安卓基础知识系列旨在简明扼要地提供面试或工作中常用的基础知识,让对安卓还不太熟悉的小伙伴更快地入门。同时自己在工作中,也没法完全记住所有的基础细节,写这样的系列文章,可以让自己形成一个更完备的知识体系,同时给自己日后留个知识参考。 开始的开始 View 事件分发机制是我觉得非常有意思的内容,依稀记得我第一次看完时恍然大悟的感觉,不禁赞叹设计者优秀的开发思维,居然能想到这么有才的事件分发方法,我内心十分佩服。今天回过头来重温了一遍事件分发机制的内容,我依然觉得精彩,本篇内容就让我们来探究 View 的事件.

qq_40987010的博客 1896

安卓View—事件分发机制(二)

安卓View—事件分发机制 文章目录安卓View—事件分发机制一、基础知识1.事件分发是什么2.点击事件的传递规则3.事件分发的顺序二、事件分发源码分析1.Activity对点击事件的分发过程2.ViewGroup对点击事件的分发过程3.View对点击事件的分发过程三、事件分发总结 一、基础知识 1.事件分发是什么 事件分发就是对MotionEvent事件的分发过程,即当一个MotionEvent...

睡客的博客 1752

UVM环境复位--stop_sequences()

在UVM验证环境中, stop_sequences是一个用于强制终止所有正在运行的 Sequence 的方法,通常用于动态控制激励生成流程。1.通过uvm_config_db传递事件和严格的同步机制,此方案符适用于复杂复位场景和动态测试控制。组件耦合:Driver 和 Sequence 不再直接依赖env,通过标准接口通信。竞争条件:确保 Driver 完成清理后再终止 Sequence。代码健壮性:使用非阻塞操作和事件监听,避免死锁。

qq_42779035的博客 3014

Android事件分发机制完全解析(二) :View的事件分发机制

View的事件分发机制

微不足道的博客 1855

SDK报错(1)undefined reference to `f_mount‘

按文中说法是ff.c文件中用了一个if语句来判断是否启用ff.h头文件,但是却没有地方进行宏定义来满足这个if条件。利用SDK读取sd卡时,添加了xilffs库,而且包含了ff.h头文件,还是对fat库的函数报错。网上有的说在ARM v7 gcc linker中添加xilffs的方法可以解决,但我试了没有用。如下图,我们可以在ff.c中自己添加一个宏定义来实现这个条件。最后在赛灵思论坛找到了一个解决方法,原文连接如下。这时候保存编译之后,报错就消失了。ff.c 文件在bsp工程下。

EfunStudy的博客 1481

LDPC码译码原理——概率公式推导

怎么说呢,一直以来都想写一下博客。近半年多来我一直在学习LDPC码译码上的东西,主要是在FPGA实现上的,所以这次想写一些关于这方面的内容,包括译码的原理、仿真以及实现。(当然是基于准循环LDPC码上实现的)不过呢,我写这个的初衷是为了让初学者理解入门用的,而不是在大牛面前班门弄斧,有错误之处欢迎大家批评指正。不知道会不会有人一开始像我一样,为了学好LDPC码,先去好好了解其它的诸如RS码或者是卷...

stand_by_me123的博客 2万+

Android View(二)——View的事件分发机制

文章目录一.Activity的层级结构二.事件分发的基础认识1.事件分发是什么2.事件分发过程中的三个重要方法二.事件分发的过程了解1.图解:1.1基本过程图解1.2 关于ACTION_MOVE 和 ACTION_UP2. demo验证上述过程三.onTouch、onClick、onLongClick的调用顺序四.事件分发源码分析1.Activity的事件分发2.ViewGroup的事件分发机制3.View的事件分发机制五.事件分发的总结六.参考资料 一.Activity的层级结构 在了解View的事件分发

haazzz的博客 2094

告别CPU空转!用STC8的SPI+DMA高效驱动上百颗WS2812B灯珠

本文详细解析了如何利用STC8单片机的SPI+DMA外设高效驱动WS2812B全彩灯珠,解决传统软件延时驱动方式在长灯带应用中的性能瓶颈。通过硬件方案设计、数据格式转换和DMA传输配置,实现高达400Hz的刷新率和低于5%的CPU占用率,适用于大规模灯光项目。

weixin_30847939的博客 394

Android事件分发机制(二)——View

在分析分发机制之前,我们来了解一些预备知识。 onTouch是优先于onClick执行,事件传递的顺序是先经过onTouch,再传递到onClick; MotionEvent对象的四种状态: MotionEvent.ACTION_DOWN:手指按下屏幕的瞬间。 MotionEvent.ACTION_MOVE:手指在屏幕上移动 MotionEvent.ACTION_UP:手指离开屏幕瞬间 Mot...

Flying snow 920

拯救者R7000用户实测:用华为电脑管家11.0版搞定MatePad Pro多屏协同(附驱动与显卡避坑指南)

本文详细介绍了如何在非华为笔记本联想拯救者R7000上安装华为电脑管家11.0版,实现与MatePad Pro的多屏协同功能。从驱动优化到显卡配置,提供了全面的避坑指南和实用技巧,帮助用户解决连接失败等常见问题,提升跨设备生产力体验。

weixin_30788619的博客 398

three.js 载入 3D 模型的方法

三维模型的加载器ColladaLoader模型加载器。GLTFLoader模型加载器。OBJLoader模型加载器。FBXLoader模型加载器。

w418856的博客 4362

【Android 事件分发】事件分发源码分析 ( ViewGroup 事件传递机制 二 )

Android 事件分发 系列文章目录、 前言、 一、获取触摸索引值、 二、按照 Z 轴深度排序组件、 三、获取子组件、 四、ViewGroup 事件分发相关源码、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 1549

基于特征模仿的YOLOv5中间层知识蒸馏:原理、实现与实验全解析

目标检测中的模型轻量化是一个关键挑战。本文提出一种基于特征模仿(Feature Imitation)的YOLOv5中间层知识蒸馏方法,通过让学生模型学习教师模型的中间层特征表示,显著提升轻量级检测器的性能。我们将详细阐述蒸馏损失函数的设计、特征对齐策略、训练流程,并提供完整可运行的代码实现。同时,推荐多个适合蒸馏训练的数据集,并通过实验验证方法的有效性。

YOLO 185

浅谈Android 事件分发机制(二)

在上一篇文章中,浅谈Android 事件分发机制(一),简要分析了一下事件分发机制的原理,总结一下就是事件层层传递,直到被消费,原理看似简单,但是在实际使用过程中,场景各不相同,复杂程度也就因产品而异,这篇文章就通过给view加移动来模拟事件分发。 触摸事件 这里涉及到几个与手指触摸相关的常见事件: 坐标系对于单指触控移动来说,一次简单的交互流程是这样的: 手指落下(ACTION_DOW...

qq_43093708的博客 1132

面试问题总结——关于OpenCV(一)

整理了一下网上和我面试中遇到的关于OpenCV相关的问题。 其中因为我的简历中有个项目用到了特征点检测相关的知识,所以整理了SIFT/SURF和FLANN。 有些知识点也不深入,对于写的不对的地方,欢迎指正。 关于OpenCV的内容 1.OpenCV中cv::Mat的深拷贝和浅拷贝问题   深拷贝:分配新内存的同时拷贝数据,当被赋值的容器被修改时,原始容器数据不会改变。   浅拷贝:仅拷贝数据,当被赋值容器修改时,原始容器数据也会做同样改变。 OpenCV的Mat时,有几种赋值方式分别为:   深.

boss-dog 1万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Android 事件分发机制(二)

常见事件 既然是事件分发,总要有事件才能分发吧,所以我们先了解一下常见的几种事件。 根据面向对象思想,事件被封装成 MotionEvent 对象,由于本篇重点不在于此,所以只会涉及到几个与手指触摸相关的常见事件: 事件简介 ACTION_DOWN 手指初次接触到屏幕时触发。 ACTION_MOVE 手指在屏幕上滑动时触发,会会多次触发。 ...

aicyo8644的博客 148

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Android事件分发机制二:viewGroup与view对事件的处理

前言 很高兴遇见你~ 在上一篇文章 Android事件分发机制一:事件是如何到达activity的? 中,我们讨论了触摸信息从屏幕产生到发送给具体 的view处理的整体流程,这里先来简单回顾一下: 触摸信息从手机触摸屏幕时产生,通过IMS和WMS发送到viewRootImpl viewRootImpl把触摸信息传递给他所管理的view view根据自身的逻辑对事件进行分发 常见的如Activity布局的顶层viewGroup为DecorView,他对事件分发方法进行了重新,会优先回调windowCall

一只修仙的猿 1065

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Android事件分发机制详解(二)

在上一篇文章Android事件分发机制详解(一)中,介绍了View的事件分发,这篇文章主要介绍ViewGroup的事件分发机制以及点击和触摸事件是怎么传递的。ViewGroup事件分发在上一篇文章中,我们分析过在点击或者触摸View后,事件首先是传到View的dispatchTouchEvent方法中处理,在ViewGroup也是同样的,首先也传到ViewGroup中的dispatchTouchEv

secray的博客 293

android事件分发机制分析(二)

dispatchTransformedTouchEvent 如果不是cancel的话,尽管pointerId可能有所不同,但是大体逻辑还是一样的,如果传入的view为null,将ViewGroup视为一个普通的view,调用dispatchTouchEvent,否则调用的dispatchTouchEvent。对于pointerId的不同的情况,会将event的pointerId赋值为新的再传递下去...

ljt326053002的博客 268

Android事件分发机制深度分析(二)

从Activity到根ViewGroup事件分发的源码解析 上篇有提到点击事件经过层层传递来到了当前Activity,当事件到达当前Activity时,会调用Activity#dispatchTouchEvent方法: public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == Moti...

Markus 357

【Android View事件(二)】详解事件分发机制

Android事件分发机制不仅仅是核心知识更是难点,这对于不少初学者甚至是中级开发者来说都会觉得困惑。另外,View的另一大难题就是滑动冲突,解决它的方法就不需要掌握事件分发机制作为理论基础,因此掌握好View的事件分发机制是十分重要的。 本篇文章将以图文结合的方式,深入介绍View的事件分发机制。而后面的文章我将会详细分析View 的滑动以及滑动冲突,敬请期待。

大圣代的技术专栏 1204
上一篇: Android事件分发机制(一)
下一篇: C语言基础知识总结(二)
钱多多~吖
博客等级 码龄13年 4粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值