[Android]视图的控触操作-MotionEvent

article/2025/9/14 14:29:55

 引入

对屏幕的任何操作,系统都会创建一个触摸事件的对象MotionEvent来应对这个操作。当点击手机屏幕的某一个视图时,最先感应到的是屏幕,因为Activity系统是分层的结构,底层是一些驱动,所以驱动就会得到信息并且把信息传到被点击的应用,应用再交给Activity,Activity通过MotionEvent对象来实现对视图的触控操作,那么接下来我们学习一下MotionEvent对象如何实现对视图的触控操作。


一、事件的操作类型

正常情况下,一次手指触摸屏幕的行为会引起一系列的点击事件,MotionEvent对象存在变量action来反映这一系列点击事件的操作类型,所以我们可以通过MotionEvent对象的action变量的值来得到当前的点击状态。

  • 手指按下时,action的值等于ACTION_DOWN,等于0
  • 手指在屏幕上移动时,action的值等于ACTION_MOVE,等于2
  • 手指离开屏幕,action的值等于ACTION_UP,等于1

单点触控一次简单的交互流程有两种情况:

  • 手指按下,马上离开,action的值的变化为0->1
  • 手指按下,在屏幕上移动一段距离后离开屏幕,action的值的变化为0->2->...->2->1


二、MotionEvent的传递,消耗,处理过程

事件分发的三个重要方法:

       1、dispatchTouchEvent()方法:会从Activity开始一层一层地向子View分发事件,直到没有子           View。(分发的时候,只能是View分发给子View,不能View分发给孙View)

        2、onTouchEvent()方法:会在dispatchTouchEvent()方法调用到最底层View之后,再从最底           层View一层一层地往上回调,如果某个View的onTouchEvent方法返回true,那么就会停止            向上回调。

        3、onInterceptTouchEvent方法:伴随着dispatchTouchEvent()方法存在,它的作用就是拦截          ViewGroup的事件,不让它继续向下分发事件。

Activity,View,ViewGroup和MotionEvent的主要方法:

Activity:

dispatchTouchEvent(ev: MotionEvent?): Boolean分发事件
onTouchEvent(ev: MotionEvent?): Boolean处理事件的回调

View:

dispatchTouchEvent(ev: MotionEvent?): Boolean分发事件
onTouchEvent(ev: MotionEvent?): Boolean处理事件的回调
setOnTouchListener(l:OnTouchListener)设置事件监听器
setOnClickListener(l:OnClickListener)设置点击监听
setOnLongClickListener(l:OnClickListener)设置长按监听
setOnCreateContextMenuListener(l:OnCreateContextMenuListener)用于创建菜单

注意:OnTouchListener中的onTouch()事件优先级高于onTouchEvent()事件,如果onTocuh()的返回结果为ture,那么该View的onTouchEvent()事件将不会被调用。

ViewGroup:

dispatchTouchEvent(ev: MotionEvent?): Boolean分发事件
onInterceptTouchEvent(ev: MotionEvent?): Boolean
拦截事件

注意:onInterceptTouchEvent方法只在ViewGroup中可以重写。

MotionEvent:

同时通过MotionEvent对象我们可以得到点击事件的x和y轴坐标。

系统提供的方法如下:

getX()得到事件发生的x轴坐标(相对于当前视图)
getY()得到事件发生的y轴坐标(相对于当前视图)
getRawX()得到事件发生的x轴坐标(相对于屏幕左顶点)
getRawY()得到事件发生的y轴坐标(相对于屏幕左顶点)

 下面我们来理解一下MotionEvent的传递,消耗,处理过程

如图所示,当点击事件产生之后,事件首先会传递给当前的Activtiy,Activity会调用分发事件方法dispatchTouchEvent将事情传递给最大的View,然后再一层层地向下传递给子View,直到传递到最小的view,调用最小的view的onTouchEvent方法,向上传递,直到有一个view的onTouchEvent方法返回true,消耗这个点击事件,消耗这个点击事件之后就不会向上传递了。如果没有,那么事件最终会被activity消耗。

通俗点说就是:爷爷(Activity)得到了一个苹果(点击事件),爷爷把苹果给了爸爸(View),爸爸把苹果给了我(子View),如果我选择不吃苹果,那么就把苹果给爸爸,如何爸爸如果选择吃了苹果,就是把苹果消耗了,如果爸爸选择不吃苹果,就把苹果给爷爷,爷爷只能吃掉苹果,结束。

通过代码加深理解MotionEvent的传递,消耗,处理过程

当View的onTouch和onTouchEvent方法都返回false时

点击一下View,产生的点击事件如下:

点击View并移动,产生的点击事件如下:

最终都是Activity消费了点击事件。

当View的onTouch方法返回true时:

点击一下View,产生的点击事件如下:

 

 点击View并移动,产生的点击事件如下:

最终都是View消费了点击事件,并且可以看出OnTouchListener中的onTouch()事件优先级高于onTouchEvent()事件,如果onTocuh()的返回结果为ture,那么该View的onTouchEvent()事件将不会被调用。

小项目

先看效果图:

 

  • 功能描述

            通过手指移动来拖动图片

           控制图片不能超过屏幕显示区域

  • 技术点

         MotionEvent处理

         对View进行动态定位(layout)

代码:

class MainActivity : AppCompatActivity(),View.OnTouchListener{var lastX=0var lastY=0lateinit var imageView: ImageViewlateinit var parentView:RelativeLayoutvar maxRight=0var maxBottom=0override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)imageView=findViewById(R.id.imageView4)parentView=imageView.parent as RelativeLayoutimageView.setOnTouchListener(this)}override fun onTouch(p0: View?, event: MotionEvent): Boolean {val eventX=event.rawXval eventY=event.rawYwhen(event.action){MotionEvent.ACTION_DOWN->{if(maxRight==0){maxRight=parentView.rightmaxBottom=parentView.bottom}lastX= eventX.toInt()lastY=eventY.toInt()}MotionEvent.ACTION_MOVE->{var dx:Int=(eventX-lastX).toInt()var dy:Int=(eventY-lastY).toInt()var left=imageView.left+dxvar top=imageView.top+dyvar right=imageView.right+dxvar bottom=imageView.bottom+dy//限制left>=0if(left<0){right+=-leftleft=0}//限制top>=0if(top<0){bottom+=-toptop=0}//限制right<maxRightif(right>maxRight){left-=right-maxRightright=maxRight}//限制bottom>=0if(bottom>maxBottom){top-=bottom-maxBottombottom=maxBottom}imageView.layout(left, top, right, bottom)lastX=eventX.toInt()lastY=eventY.toInt()}}return true}
}


http://chatgpt.dhexx.cn/article/gUG0Q6fn.shtml

相关文章

MotionEvent 详解

Android MotionEvent详解: https://www.jianshu.com/p/0c863bbde8eb https://www.diycode.cc/topics/392 Android 将所有的输入事件都放在了 MotionEvent 中&#xff0c;随着安卓的不断发展壮大&#xff0c;MotionEvent 也开始变得越来越复杂&#xff0c;下面是我自己整理的 …

MotionLayout MotionScene 动画从未如此简单!

话不多说先上图。 这是要做的最终效果。通过这些动画我们将了解MotionLayout的使用方法和常用的一些属性。 第一步&#xff1a;添加依赖 如果要使用MotionLayout请将ConstraintLayout更新到2.0及以上。在build.gradle文件中添加依赖 如果使用的是AndroidX&#xff0c;添加依赖…

Android的MotionEvent和事件处理

之前几篇文章我们讲解了自定义View和ViewGroup, 今天我们来看下View和ViewGroup常见的触摸事件和按键事件。 MotionEvent MotionEvent对象是与用户触摸相关的时间序列&#xff0c;该序列从用户首次触摸屏幕开始&#xff0c;经历手指在屏幕表面的任何移动&#xff0c;直到手指…

MotionEvent详解

Android MotionEvent 详解&#xff0c;之前用了两篇文章 事件分发机制原理 和 事件分发机制详解 来讲解事件分发&#xff0c;而作为事件分发主角之一的 MotionEvent 并没有过多的说明&#xff0c;本文就带大家了解 MotionEvent 的相关内容&#xff0c;简要介绍触摸事件&#xf…

Android自定义View进阶-MotionEvent详解

欢迎Follow我的GitHub, 关注我的CSDN. 其余参考Android目录 我们微信公众号&#xff1a;杨守乐 推荐文章&#xff1a; 如果你喜欢上了一个程序员小伙&#xff0c;献给所有的程序员女友 学习资料&#xff08;干货汇集&#xff09;不断更新【更新于2017-2-25】 Android Studi…

常用awk命令整理

AWK倾向于一行一行的数据进行处理 awk 用法&#xff1a;awk pattern {action} 变量名 含义 ARGC 命令行变元个数 ARGV 命令行变元数组 FILENAME 当前输入文件名 FNR 当前文件中的记录号 FS 输入域分隔符&#xff0c;默认为一个空格 RS 输入记录分隔符 NF 当…

sed命令和awk命令

sed命令 sed命令■什么是sed■sed的工作流程■命令格式■常用选项:■常用操作:■打印内容■sed编辑器的寻址方式■删除行■替换■插入 awk命令■awk命令的工作原理■命令格式■常见的内建变量■按行输出文本■按字段输出文本:■通过管道、双引号调用Shell 命令■拓展 sed命令 …

awk命令应用

记录&#xff1a;353 场景&#xff1a;在CentOS 7.9操作系统上&#xff0c;使用awk文本处理工具处理文本&#xff1b;使用awk、cat和grep搭配使用处理文本&#xff1b;使用awk直接处理文本&#xff1b;使用shell脚本调用awk脚本处理文本。 版本&#xff1a; 操作系统&#x…

概要设计之功能模块

功能模块描述 所谓功能模块&#xff0c;从字面上理解&#xff0c;就是以功能来进行划分模块。 接着&#xff0c;根据功能特性多少&#xff0c;决定是否要划分“子功能模块”。 这里就容易出现一个问题&#xff0c;如何去确定每个功能的界限呢&#xff0c;以及很多人会拿用户角…

系统架构图编写(概要设计)

系统架构图编写&#xff08;概要设计&#xff09; 应用架构图、技术架构图、业务架构图定义以及到底怎么画好架构图&#xff1f; 常见的数据库架构设计方案&#xff1f; 业务架构的定义、特性和方法 架构图之间的关系 业务架构图 业务架构&#xff0c;是IT架构的基础。 是从业…

概要设计、详细设计:概念、方法、实践步骤

完整软件开发流程&#xff1a; 需求分析、概要设计、详细设计 一 1. 概念、方法、实践步骤 设计是指根据需求开发的结果&#xff0c;对产品的技术实现由粗到细进行设计的过程。根据设计粒度和目的的不同可以将设计分为概要设计、详细设计等阶段以便于管理和确保质量。设计内容…

概要设计与详细设计如何编写

撰写的设计文档主要分为&#xff1a;总体概要设计文档 详细设计文档&#xff0c;后简称为“概设”“详设”。 总设和详设都应该包含的部分&#xff1a; &#xff08;1&#xff09; 需求&#xff1a;一般以产品的语言描述&#xff0c;这一块可以拷贝产品需求文档中的story li…

软件项目总体设计

软件项目总体设计 目录 1.导言 1 1.1目的 1 1.2范围 1 1.3参考资料 2 2.项目设计原则简介 2 3.功能模块设计 2 3.1功能模块设计总述 2 3.2 客户端子系统模块设计 4 3.2.1 模块 CM1 &#xff1a;静态页面 4 3.2.2 模块 CM2&#xff1a;系统登录 5 3.2.3 模块 CM3 &#xff1a;注…

软件概要设计的过程与任务

在完成对软件系统的需求分析之后&#xff0c;接下来需要进行的是软件系统的概要设计。一般说来&#xff0c;对于较大规模的软件项目&#xff0c;软件设计往往被分成两个阶段进行。首先是前期概要设计&#xff0c;用于确定软件系统的基本框架&#xff1b;然后是在概要设计基础上…

软件工程技术--第四章 概要设计

第四章 概要设计 4.1 软件设计概述 4.1.1 软件设计的概念与重要性 ​ 软件设计是软件工程的重要阶段&#xff0c;是一个将软件需求转换为软件表示的过程。软件设计的基本目标是用比较抽象概括的方式确定目标系统如何完成预定的任务&#xff0c;即确定系统的物理模型&#xff0…

ios 新建项目关于Main.storyboard的处理

使用xcode新建新建项目时&#xff0c;都会带一个main.storyboard的主界面。如果你不进行代码控制&#xff0c;默认APP启动会加载main.storyboard这个界面。怎么使用这个界面来加载这里就不在介绍了&#xff0c;这里只说用代码加载主页&#xff0c;不使用main.storyboard时&…

storyboard 使用

Storyboard是一项令人兴奋的功能&#xff0c;在iOS5中首次推出&#xff0c;在开发app的界面时可以极大地节省时间。 如下图所示&#xff0c;这就是一个完整的应用的storyboard&#xff0c;接下来我们要学习如何通过这种方式创建应用。 现在你可能还不是很精确地知道我们的应用可…

ios storyboard简单用法

使用xcode5中的storyboard&#xff0c;做个简单的界面&#xff0c;第一次用简直一头雾水&#xff0c;摸索下来感觉也蛮方便的。 从左到右&#xff0c;从上到下&#xff0c;控件依次是&#xff1a;UITextFiled&#xff0c;UIButton&#xff0c; UILabel&#xff0c; UIPickerVi…

iOS开发18:Storyboard的简单使用

之前做的例子&#xff0c;我们经常会用到.xib文件&#xff0c;在其中我们可以进行界面的设计。不过如果想切换视图&#xff0c;我们就得自己写很多代码。自从苹果推出了Storyboard&#xff0c;我们可以在一个编辑区域设计多个视图&#xff0c;并通过可视化的方法进行各个视图之…

如何在xcode中使用storyboard

StoryBoard是iOS 5的新特征&#xff0c;目的是代替历史悠久的NIB/XIB&#xff0c;对于已经习惯了xib文件的孩子们来说&#xff0c;StoryBoard还不是那么熟悉。经过两天的研究&#xff0c;有了一些心得&#xff0c;在此分享。 一、如何使用storyboard简单实现Push页面&#xff…