Android图解浅析事件拦截机制

Android事件拦截 背景 之前有同事吐槽Android的事件分发拦截框架对于事件的拦截的方式和返回值比较乱,不同的地方需要返回不同的值,因此希望撰写一篇文档以作记录。 本文主要分析触摸事件和按键事件在不同阶段被拦截的流程,总结在不同阶段不同方法中返回值的含义。 按键的拦截 interceptKeyBeforeQueueing 在inputflinger分发keyevent前,会先将event上报给PhoneWindownManager处理,如果PhoneWindowManager消费掉,则不会继续分发给应用。这个Ph 阅读详情

当Android系统捕获到用户的各种输入事件后,如何准确的传递给真正的需要这个事件的控件?Android提供了一整套完善的事件传递、处理机制,来帮助开发者完成准确的事件分配与处理,这里我就不分析源码了,简单点,图形化分发过程,便于理解,待到后期分析dispatchTouchEvent源码时,回想这个图解,会方便理解很多。

当我们点击一个按钮时,通常会产生两个或者三个事件---按下、滑动(可能无)、抬起。Android为触摸事件封装了一个类----MotionEvent,其中假如我们重写一个view的onTouchEvent事件中的参数就是一个MotionEvent。由于Android的View结构是树形结构,也就是说,View可以放在ViewGroup里面,通过不同的组合来实现不同的样式。View可以放在一个ViewGroip,而这个ViewGroup又放在另一个ViewGroup里面,甚至还有可能继续嵌套。可能同一个事件,子View和ViewGroup都有可能想要进行处理,因此怎么样去“分发“和“拦截”的问题就产生了。

假设有这么一个View,一个ViewGroupA,里面嵌套了另一个ViewGroupB,而ViewGroupB里面有一个view。整体的布局结构如下:


布局文件如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.viewdispatch.MainActivity" >

    <com.example.views.MyViewGroupA
        android:layout_width="260dp"
        android:layout_height="360dp"
        android:background="#f42c61" >

        <com.example.views.MyViewGroupB
            android:layout_width="200dp"
            android:layout_height="300dp"
            android:background="#042c61" >

            <com.example.views.MyView
                android:layout_width="160dp"
                android:layout_height="260dp"
                android:background="#cccccc" />
        </com.example.views.MyViewGroupB>
    </com.example.views.MyViewGroupA>

</RelativeLayout>

整体的Activity包含3个自定义的View,项目结构是MyView、MyViewGroupB、MyViewGroupA。所以整体Touch事件的主角是View和ViewGroup,而与View相关的Touch事件有2个dispatchTouchEvent和onTouchEvent;与ViewGroup相关的Touch事件有3个dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。所以我们在定义好View和ViewGroup后,让其分别是实现这些方法。

代码如下:

MyView.java

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {
	private String Tag = "MyView";

	public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public MyView(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(Tag, "----->MyView");
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->onTouchEvent");
		return super.onTouchEvent(event);
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->dispatchTouchEvent");
		return super.dispatchTouchEvent(event);

	}

}
MyViewGroupA.java
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.LinearLayout;

public class MyViewGroupA extends LinearLayout {
	private String Tag = "MyViewGroupA";

	public MyViewGroupA(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		// TODO 自动生成的构造函数存根
	}

	public MyViewGroupA(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(Tag, "----->MyViewGroupA");
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
		Log.e(Tag, "----->dispatchTouchEvent");
		return super.dispatchTouchEvent(ev);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		Log.e(Tag, "----->onInterceptTouchEvent");
		return super.onInterceptTouchEvent(ev);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		Log.e(Tag, "----->onTouchEvent");
		return super.onTouchEvent(event);
	}

}
MyViewGroupB和A一样,就不贴了。

其中上面事件的传递的返回值是这样的,如果返回true,表示该View(ViewGroup)拦截了,不继续往下分发事件了,如果返回false,表示不拦截,继续往下分发。默认的调用父方法super.xxx是表示不拦截的意思。

下面就开始来验证吧。

运行我们的项目,先看看我们3个view的加载情况吧:


可以看出是由外到内加载的。

好了,开始touch事件吧,现在我们先点击最外层粉红的ViewGroupA,观察Log输出:


然后点击蓝色区域的ViewGroupB,再观察Log输出:


最后点击MyView观察输出


由此,我们可以大致的绘制出如下图所示的这样的一个图解流程。


现在假如我们修改MyViewGroupA中的onInterceptTouchEvent()事件,将其返回值改为True,点击任意一层view,现在我们再看log输出:


可以看出只有A的3个事件进行了处理,由此事件被A拦截了。流程图如下所示:


同理,将A的返回值改回来,我们修改MyViewGroupB的onInterceptTouchEvent()方法,也返回true,然后点击MyView或者MyViewGroupB,试试。Log输出如下:


也就是事件只是分发到了MyViewGroupB,没有到MyView,整个流程图如下所示:


最后,假如底层的MyView想处理呢,相应的我们只用修改下onTouchEvent()的返回值就好,将其改为返回true.然后点击MyView看看log输出。


流程图是这样的:





好了,文章到此结束,先简单的对分发和拦截有个大致的了解,但事件分发机制还没完全分析完,等待下一篇再来分析。

如果觉得分析的不过瘾,可以继续对此进行源码的分析,借用大神的分析博客,结合本篇的图解,相信本文应该还是有帮助的吧。喜欢的话,点个赞,留个言~

庖丁解牛,继续分析:

http://blog.youkuaiyun.com/guolin_blog/article/details/9097463

http://blog.youkuaiyun.com/guolin_blog/article/details/9153747


最后,如果对文章有什么疑惑,欢迎指出,共同进步!




Android 输入事件拦截机制详解 Android 中的输入事件类型包括触摸事件(Touch Events)、键盘事件(Key Events)、轨迹球事件(Trackball Events)等。通过拦截和处理输入事件,我们可以灵活地控制事件的传递和处理流程。本文详细介绍了 Android 输入事件拦截机制的概念,并提供了相应的源代码示例。在 Android 开发中,输入事件拦截机制是实现用户交互的重要组成部分。下面是一个简单的示例,演示了如何在 Android 中使用输入事件拦截机制。方法中,我们根据触摸事件的不同动作进行相应的处理。 阅读详情

相关推荐

rv1126 读取sensor输入,输出到屏幕显示【RK_MPI API接口】

rv1126 libdrm VO

学习记录 1万+

Android中级——事件拦截机制和滑动冲突

若MyViewGroupA的onInterceptTouchEvent()方法返回True,打印如下。若MyViewGroupB的onInterceptTouchEvent()方法返回True,打印如下。若MyViewGroupB的onTouchEvent()方法返回True,打印如下。布局如下,MyViewGroupA包裹MyViewGroupB再包裹MyView。若MyView的onTouchEvent()方法返回True,打印如下。点击最内层蓝色的MyView,打印如下。

松仔Log的博客 1233

从零到一:手把手教你用Python搭建医学影像识别CNN模型(附完整代码)

本文详细介绍了如何使用Python和TensorFlow/Keras从零开始构建一个医学影像识别的CNN模型,涵盖数据预处理、模型架构设计、训练调优及部署全流程。通过实战案例和完整代码,帮助开发者快速掌握深度学习在医学影像识别中的应用,特别适合医疗AI领域的初学者和研究者。

spark7igniter的博客 200

【Android】事件的拦截和分发机制

事件的拦截和分发机制

每天不是在写bug就是在写bug的路上 678

Keil中搭建自动化单元测试框架Unity

前言:   虽然一些C++的自动化单元测试框架也能用来C语言单元测试,但那样我们编写C语言程序时需要符合C++的标准,这样有一些C的特性是无法使用的,限制C的特性使用不太好,于是找了一个全部用C实现的自动化测试框架。Unity是一个简单且直接的自动化单元测试框架,它由很少的几个文件构成。 搭建环境:   1.从github上下载最新版本的Unity源码,下载链接:https://github...

程序员的自我修炼 3899

手把手教你为ArduPilot添加自定义飞行模式:以自动巡检航线为例

本文详细介绍了如何为开源飞控ArduPilot添加自定义飞行模式,并以自动巡检航线为例,提供了从状态机设计、代码实现到地面站集成的完整开发指南。通过七步法手把手教学,帮助开发者深入理解飞控核心逻辑,实现无人机自主执行复杂巡检任务,满足行业应用定制需求。

weixin_29306875的博客 135

Android view 事件分发流程(四)--- 事件拦截

事件拦截就是拦截事件分发到子View中去。事件拦截的方式有两种:内部拦截和外部拦截。move事件 → 子View在dispatchTouchEvent方法中调用getParent().requestDisallowIntercepteTouchEvent(false) → mGroupFlags = 0 → disallowIntercept = false → intercepted = onInterceptTouchEvent(ev);

a18211246446的博客 1245

移位寄存器——用Verilog实现串入串出、串并和并串转换并进行Modelsim仿真

用Verilog实现串并转换 首先我们先要了并串和串并转换的原理 并串转换:先将八位数据暂存于一个八位寄存器器中,然后左移输出到一位输出端口,这里可以通过一个“移位”来实现,相当于实现了移位寄存器的功能。 串并转换:新输入的位值成为原来数据的最低位,将原来数据的最高位舍去,这里可以通过一个简单的“连接符”来实现。 我们这里采用两种方式来进行串并转换 一:lsb优先 Least Significant Bit,最低比特,最低位优先 二:msb优先 Most Significant Bit,最高比特,

H19981118的博客 2万+

Android滑动冲突解决方案内外部拦截法及原理

本文接上篇Android滑动冲突一内部拦截外部拦截简介 一 ViewPager嵌套ListView的滑动冲突,内部拦截法为何ViewPager的onInterceptTouchEvent要做判断而不是直接返回true? 我们重温下Android事件分发二之ViewGroup如何处理事件中ViewGroup事件分发方法的源码。注意这个ViewGroup对应到我们例子的ViewPager class:ViewGroup: @Override public boolean dispa.

LJ_GOD的博客 5976

弹窗提示报错: F:\c\CFX5\bin\Debug\net9.0-windows10.0.26100.0\CFX5.dll 面向无法动态枚举工具箱项目的平台...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 945

FastAPI 极简教程(偏实战,一篇搞定)

本文是一篇FastAPI实战教程,通过最少的概念讲解快速掌握FastAPI的核心功能。文章首先介绍FastAPI是基于Starlette和Pydantic的高性能Python API框架,具有自动生成文档、类型驱动校验、异步支持和依赖注入等优势。教程从安装环境开始,演示了如何创建最小项目并编写第一个"Hello World"接口。接着详细讲解了路由参数处理(Path/Query/Body)、Pydantic数据模型校验、响应模型控制、状态码设置等核心功能。在高级功能方面,重点介绍了错误处

AI天才研究院 812

Android 事件拦截/分发机制 (图解+代码)

一、介绍Android为触摸事件封装了一个类MotionEvent,其实OnTouchEvent的一个参数就是MotionEventMotionEvent中封装了触摸点坐标、点击事件类型等Android中的View可以放在一个ViewGroup中,这个ViewGroup又放在另一ViewGroup中等等,一层层嵌套起来,同一个触摸事件,View和父ViewGroup都想要处理,我们应该传给谁呢,此...

0729Liang 7636

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

反思|Android 事件拦截机制的设计与实现

「反思」 系列是笔者一个新的尝试,其起源与目录请参考 这里 。 概述 完整的掌握 Android 事件分发体系并非易事,其整个流程涉及到了 系统启动流程(SystemServer)、输入管理(InputManager)、系统服务和UI的通信(ViewRootImpl + Window + WindowManagerService)、View层级的 事件分发机制 等等一系列的环节。 事件拦截机制...

却把清梅嗅的博客 2196

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Android事件拦截(3)——系统拦截和应用拦截

本文主要分析触摸事件和按键事件在不同阶段被拦截的流程,总结在不同阶段不同方法中返回值的含义。

Flying snow 5535

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

安卓事件分发机制、拦截和消费机制的总结

▐ 事件分发:public boolean dispatchTouchEvent(MotionEvent ev) Touch 事件发生时 Activity 的 dispatchTouchEvent(MotionEvent ev) 方法会以隧道方式(从根元素依次往下传递直到最内层子元素或在中间某一元素中由于某一条件停止传递)将事件传递给最外层 View 的 dispatchTouchEve

oDaBenNiu的博客 1082

android View事件分发和事件拦截

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。用来事件的分发,如果事件能够传递给当前的View,那么此方法一定会被调用,返回的结果受到当前View的onTouchEvent和下级的dispatchTouchEvent方法的影响。在dispatchTouchEvent方法中调用,用来处理点击的事件,返回结果是否消耗当前事件,如果不消耗,如果不消耗,则在同一个事件的序列中,当前View无法再次接收到事件。

2401_84009215的博客 790

Android事件拦截(一)——触摸事件MotionEvent分析

MotionEvent相关动作分析

Flying snow 1789

Android事件的分发与拦截机制

前言 Android为我们提供了丰富的View及ViewGroup控件,使得我们可以轻松的地完成Android应用界面的绘制,同时还可以自定义精美的View控件。绘制一个界面往往需要众多的View及ViewGroup不断嵌套,由于View可能需要与用户交互,如Button响应用户的点击,EditText响应用户的输入,而ViewGroup也可以响应事件,当多个ViewGroup和View嵌套的时候就

宿罪的博客 2203

Android事件分发机制,事件拦截和事件响应

一直以来,搞Android得都知道,安卓处理事件时有一定的原则的,前几天给一个大二的讲Android事件分发,不知道她听懂了没,打着这种情况我还是记录一下我是怎么了解Android事件分发的吧,希望能帮不少人! 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_MOVE...->ACTION_MOV

被世界遗弃的江的博客 1097

2024年最全反思|Android 事件拦截机制的设计与实现,面试万能总结语

想要说清事件分发机制和事件拦截机制事件序列是首先要理解的概念。什么是事件序列?Google官方文档中对其描述为,顾名思义,我们可以将其理解为用户一次完整的触摸操作流程—— 举例来说,用户单击按钮、用户滑动屏幕、用户长按屏幕中某个UI元素等等,都属于该范畴。为什么采用链表,有没有更加简单粗暴的实现方案?

2401_84561461的博客 1006
上一篇: Android自定义ViewGroup实战-----流式布局
下一篇: java List多字段排序
android_cmos
博客等级 码龄12年 177粉丝 73原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值