当前位置: 首页 > news >正文

【Android】一个demo理解dispatchTouchEvent、onInterceptTouchEvent与onTouchEvent

简述:
事件分发机制是指Android中触摸事件MotionEvent的传递机制,传递流程是Activity->Window->DecorView->ViewGroup->View。其中有三个重要的方法:dispatchTouchEvent,onInterceptTouchEvent(ViewGroup有,View没有),onTouchEvent。

  1. dispatchTouchEvent用于分发事件,ViewGroup在此方法中,会将事件分发给对应子View。当事件被子View或者当前ViewGroup处理时,返回true。
  2. onInterceptTouchEvent用于父View拦截子View事件,若拦截成功,即返回true,则子View将不再处理后序的事件。默认是不拦截的。
  3. onTouchEvent用于响应点击,返回true代表事件被当前View处理,返回false则向上传递。

示例:
首先自定义两个View,一个继承自View,一个继承自LinearLayout:
TestView.kt

package com.example.toucheventtest.viewsimport android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.View
import com.example.toucheventtest.constant.Utilsclass TestView: View {companion object {const val TAG = "TestView"}constructor(context: Context) : super(context) {}constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}override fun onTouchEvent(event: MotionEvent?): Boolean {val viewTag = "$TAG onTouchEvent"when (event?.action) {MotionEvent.ACTION_DOWN -> {Log.d(Utils.LOG_TAG, "$viewTag down")}MotionEvent.ACTION_MOVE -> {Log.d(Utils.LOG_TAG, "$viewTag move")}MotionEvent.ACTION_UP -> {Log.d(Utils.LOG_TAG, "$viewTag up")}MotionEvent.ACTION_CANCEL -> {Log.d(Utils.LOG_TAG, "$viewTag cancel")}}return super.onTouchEvent(event)}override fun dispatchTouchEvent(event: MotionEvent?): Boolean {val viewTag = "$TAG dispatchTouchEvent"Log.w(Utils.LOG_TAG, "$viewTag Start =>")val dispatched = super.dispatchTouchEvent(event);Log.w(Utils.LOG_TAG, "$viewTag End => $dispatched")return dispatched}
}

TestLinearLayout.kt

package com.example.toucheventtest.viewsimport android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.widget.LinearLayout
import com.example.toucheventtest.constant.Utilsclass TestLinearLayout: LinearLayout {companion object {const val TAG = "TestLinearLayout"}constructor(context: Context) : super(context) {}constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {val viewTag = "$TAG onInterceptTouchEvent"when (ev?.action) {MotionEvent.ACTION_DOWN -> {Log.d(Utils.LOG_TAG, "$viewTag down")}MotionEvent.ACTION_MOVE -> {Log.d(Utils.LOG_TAG, "$viewTag move")}MotionEvent.ACTION_UP -> {Log.d(Utils.LOG_TAG, "$viewTag up")}MotionEvent.ACTION_CANCEL -> {Log.d(Utils.LOG_TAG, "$viewTag cancel")}}return super.onInterceptTouchEvent(ev)}override fun onTouchEvent(event: MotionEvent?): Boolean {val viewTag = "$TAG onTouchEvent"when (event?.action) {MotionEvent.ACTION_DOWN -> {Log.d(Utils.LOG_TAG, "$viewTag down")}MotionEvent.ACTION_MOVE -> {Log.d(Utils.LOG_TAG, "$viewTag move")}MotionEvent.ACTION_UP -> {Log.d(Utils.LOG_TAG, "$viewTag up")}MotionEvent.ACTION_CANCEL -> {Log.d(Utils.LOG_TAG, "$viewTag cancel")}}return super.onTouchEvent(event)}override fun dispatchTouchEvent(event: MotionEvent?): Boolean {val viewTag = "$TAG dispatchTouchEvent"Log.w(Utils.LOG_TAG, "$viewTag Start =>")val dispatched = super.dispatchTouchEvent(event);Log.w(Utils.LOG_TAG, "$viewTag End => $dispatched")return dispatched}
}

然后使用自定义的ViewGroup包裹自定义的View:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".TouchEventTestActivity"><com.example.toucheventtest.views.TestLinearLayoutandroid:orientation="vertical"android:layout_width="200dp"android:layout_height="200dp"android:background="#ff00ff"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"><com.example.toucheventtest.views.TestViewandroid:id="@+id/childView"android:layout_width="80dp"android:layout_height="80dp"android:layout_gravity="center"android:background="#00ffff"/></com.example.toucheventtest.views.TestLinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

效果图:
在这里插入图片描述

方法调用顺序:

  1. 不设置setOnClickListener,setOnTouchListener,setClickable。

点击/拖拽ViewGroup:
在这里插入图片描述

点击/拖拽View:
在这里插入图片描述
结论:

  • 点击或拖拽ViewGroup时仅调用了ViewGroup的dispatchTouchEvent并返回false,不调用View的dispatchTouchEvent,即不会将事件分发给View。并且会调用自身的onTouchEvent。
  • 点击或拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用了View的dispatchTouchEvent,View的dispatchTouchEvent先返回false,ViewGroup的dispatchTouchEvent再返回false,呈现递归调用。
  • 无论是点击或拖拽ViewGroup还是View,在调用ViewGroup的dispatchTouchEvent之后,都会调用一次ViewGroup的onInterceptTouchEvent。
  • 点击或拖拽ViewGroup时,会在onInterceptTouchEvent之后调用ViewGroup的onTouchEvent。
  • 点击或拖拽View时,会在onInterceptTouchEvent之后调用View的onTouchEvent,再调用ViewGroup的onTouchEvent。
  • ViewGroup和View的仅接收到down事件,且点击与拖拽没有区别。
  1. 设置View可点击,ViewGroup不可点击

点击/拖拽ViewGroup:
在这里插入图片描述
点击View:
在这里插入图片描述
拖拽View:
在这里插入图片描述
结论:

  • 点击或拖拽ViewGroup时仅调用了ViewGroup的dispatchTouchEvent并返回false,不调用View的dispatchTouchEvent,即不会将事件分发给View。
  • 点击或拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用了View的dispatchTouchEvent,View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。
  • 点击或拖拽ViewGroup时,在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且仅在down事件时被调用。
  • 点击或拖拽View时,在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且在down、move以及up时都会调用。
  • 点击或拖拽ViewGroup时,会在onInterceptTouchEvent之后调用ViewGroup的onTouchEvent,且仅在down时调用。
  • 点击或拖拽View时,会在onInterceptTouchEvent之后调用View的onTouchEvent,且在down、move以及up时都会调用。
  • Touch事件分发在拖拽时总是满足down->若干个move->up这样的响应顺序,点击时无move事件仅down->up。
  1. 设置ViewGroup可点击,View不可点击

点击ViewGroup:
在这里插入图片描述
拖拽ViewGroup:
在这里插入图片描述
点击View:
在这里插入图片描述
拖拽View:
在这里插入图片描述

结论:

  • 点击或拖拽ViewGroup时仅调用了ViewGroup的dispatchTouchEvent并返回false,不调用View的dispatchTouchEvent,即不会将事件分发给View。
  • 点击或拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用了View的dispatchTouchEvent,View的dispatchTouchEvent先返回false,ViewGroup的dispatchTouchEvent再返回true。
  • 无论是点击或拖拽ViewGroup还是View,在调用ViewGroup的dispatchTouchEvent之后,都会调用一次ViewGroup的onInterceptTouchEvent。
  • 点击或拖拽ViewGroup时,会调用ViewGroup的onTouchEvent,且在down、move以及up时都会调用。
  • 点击或拖拽View时,会在onInterceptTouchEvent之后调用View的onTouchEvent,仅在down时被调用。再调用ViewGroup的onTouchEvent,且在down、move以及up时都会调用。
  • Touch事件分发在拖拽时总是满足down->若干个move->up这样的响应顺序,点击时无move事件仅down->up。
  1. 设置均为可点击

点击ViewGroup:
在这里插入图片描述
拖拽ViewGroup:
在这里插入图片描述
点击View:
在这里插入图片描述
拖拽View:
在这里插入图片描述

结论:

  • 点击或拖拽ViewGroup时仅调用了ViewGroup的dispatchTouchEvent并返回true,不调用View的dispatchTouchEvent,即不会将事件分发给View。
  • 点击或拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用了View的dispatchTouchEvent,View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。
  • 点击或拖拽ViewGroup时,在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且仅在down事件时被调用。
  • 点击或拖拽View时,在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且在down、move以及up时都会调用。
  • 点击或拖拽ViewGroup时,会调用ViewGroup的onTouchEvent,且在down、move以及up时都会调用。
  • 点击或拖拽View时,会在onInterceptTouchEvent之后调用View的onTouchEvent,且在down、move以及up时都会调用。
  • Touch事件分发在拖拽时总是满足down->若干个move->up这样的响应顺序,点击时无move事件仅down->up。
  1. ViewGroup拦截down事件,onInterceptTouchEvent在down事件时返回true
  override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {val viewTag = "$TAG onInterceptTouchEvent"when (ev?.action) {MotionEvent.ACTION_DOWN -> {Log.d(Utils.LOG_TAG, "$viewTag down")return true}MotionEvent.ACTION_MOVE -> {Log.d(Utils.LOG_TAG, "$viewTag move")}MotionEvent.ACTION_UP -> {Log.d(Utils.LOG_TAG, "$viewTag up")}MotionEvent.ACTION_CANCEL -> {Log.d(Utils.LOG_TAG, "$viewTag cancel")}}return super.onInterceptTouchEvent(ev)}

拖拽ViewGroup:
在这里插入图片描述
拖拽View:
在这里插入图片描述
tips:点击不再列举,去掉move事件分发部分就是点击后的流程。

结论:

  • 点击或拖拽ViewGroup&点击或拖拽View表现上一致。
  • 点击或拖拽ViewGroup&点击或拖拽View,仅调用了ViewGroup的dispatchTouchEvent并返回true,不调用View的dispatchTouchEvent,即不会将事件分发给View。
  • 点击或拖拽ViewGroup&点击或拖拽View,在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且仅在down事件时被调用。
  • 点击或拖拽ViewGroup&点击或拖拽View,会调用ViewGroup的onTouchEvent,且在down、move、up时都被调用。
  1. ViewGroup拦截move事件,onInterceptTouchEvent在move事件时返回true

拖拽ViewGroup:
在这里插入图片描述
tips:点击不再列举,去掉move事件分发部分就是点击后的流程。

点击View:
在这里插入图片描述

拖拽View:
在这里插入图片描述

结论:

  • 点击或拖拽ViewGroup,仅调用了ViewGroup的dispatchTouchEvent并返回true,不调用View的dispatchTouchEvent,即不会将事件分发给View。在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且仅在down事件时被调用。还会会调用ViewGroup的onTouchEvent,且在down、move、up时都被调用。
  • 点击View时先调用了ViewGroup的dispatchTouchEvent,再调用ViewGroup的onInterceptTouchEvent,接着再调用View的dispatchTouchEvent,以及View的onTouchEvent,且在down和up时都会被调用。View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。
  • 拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用ViewGroup的onInterceptTouchEvent,在down和以及第一个move事件时调用。接着再调用View的dispatchTouchEvent,以及onTouchEvent,分发down事件,View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。move事件被拦截后,向View分发一个cancel事件。后续的move、up事件不再向View分发,不再调用View的dispatchTouchEvent&onTouchEvent以及ViewGroup的onInterceptTouchEvent,转而调用ViewGroup的dispatchTouchEvent&onTouchEvent。
  1. ViewGroup拦截up事件,onInterceptTouchEvent在up事件时返回true

拖拽ViewGroup:
在这里插入图片描述
tips:点击不再列举,去掉move事件分发部分就是点击后的流程。

点击View:
在这里插入图片描述

拖拽View:
在这里插入图片描述

结论:

  • 点击或拖拽ViewGroup,仅调用了ViewGroup的dispatchTouchEvent并返回true,不调用View的dispatchTouchEvent,即不会将事件分发给View。在调用ViewGroup的dispatchTouchEvent之后,会调用一次ViewGroup的onInterceptTouchEvent,且仅在down事件时被调用。还会会调用ViewGroup的onTouchEvent,且在down、move、up时都被调用。
  • 点击View时先调用了ViewGroup的dispatchTouchEvent,再调用ViewGroup的onInterceptTouchEvent,接着再调用View的dispatchTouchEvent,以及View的onTouchEvent,down事件正常分发,up事件被拦截后向View分发了cancel。View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。
  • 拖拽View时先调用了ViewGroup的dispatchTouchEvent,再调用ViewGroup的onInterceptTouchEvent,在down、move以及up时都会调用。接着再调用View的dispatchTouchEvent以及View的onTouchEvent,down、 move事件正常分发,up事件被拦截后向View分发了cancel。View的dispatchTouchEvent先返回true,ViewGroup的dispatchTouchEvent再返回true。
http://www.dtcms.com/a/424513.html

相关文章:

  • 十大网站平台重写Wordpress的js
  • HBase全量+增量迁移import/export方式
  • 精准交易:如何利用期权对冲你的头寸
  • 金华网站建设哪个公司好点烟台互联网公司有哪些
  • wordpress安装好了怎么登陆网站推广思路及执行方案
  • 宁波做网站皆选蓉胜网络北京网站建设推荐安徽秒搜科技
  • 注册一个个人网站工地模板图片大全
  • 知识表示与处理4
  • 网站的搜索引擎方案wordpress实例站
  • 【AI4S】大语言模型与化学的未来,以及整合外部工具和聊天机器人的潜力
  • 网站视频转码软件wordpress 图片本地化
  • 优秀的 API 接口设计规范
  • 营销网站占用多少m空间深圳 电子政务网站建设方案
  • 品牌网站建设服务商济南百度网站开发
  • 用 Python 实现一个简化但可运行的 单点登录(SSO)系统
  • 水果成篮-越短越合法
  • 外国人做的购物网站做网站开发要具备哪些素质
  • 印尼雅加达综合指数(JCI)数据对接实战指南
  • 福州网站开发公司哪些网站可以做平面设计
  • 临安规划建设局网站wordpress 评论按钮
  • 定向广播扬声器:高速公路预警新利器 为安全“喊话”
  • 做网站送优化如何做授权网站
  • 产品展示类网站网站用户体验度
  • 网站管理问题建站点的步骤
  • 安阳网站哪家做的好网站开发需要什么基础知识
  • 新乡定制网站建设公司网站建设属于
  • 网站建设技术和销售工资用手机建网站
  • 网站集群建设方案中国移动积分兑换商城官方网站
  • 怎么选择镇江网站建设WordPress影视cms
  • 网站建设的一般流程排序为湖南城乡建设部网站