综述

在上篇文章Android中的事件分发机制(上)——ViewGroup的事件分发中,对ViewGroup的事件分发进行了详细的分析。在文章的最后ViewGroup的dispatchTouchEvent方法调用dispatchTransformedTouchEvent方法成功将事件传递给ViewGroup的子View。并交由子View进行处理。那么现在就来分析一下子View接收到事件以后是如何处理的。
View的事件处理
对于这里描述的View,它是ViewGroup的父类,并不包含任何的子元素。这也就意味着View无法再次向下对事件进行分发操作,因此在View中并不存在onInterceptTouchEvent方法,也不会对事件做出拦截操作。它所做的事情就是对所接收的事件进行处理。下面就开看一下View如何对事件进行处理的。
既然ViewGroup将事件交由View的dispatchTouchEvent方。那么首先在这里就来看一下dispatchTouchEvent里面做了什么事情。
public boolean dispatchTouchEvent(MotionEvent event) {
......
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
......
return result;
}
在View的dispatchTouchEvent方法中对事件处理的核心部分体现在上述代码中。onFilterTouchEventForSecurity方法表示当前接收事件的view是否处于被遮盖状态,View处于被遮盖状态表示当前View不位于顶部,该view被其它View所覆盖。如果当前View被遮盖,那么该View不会对事件进行处理。
public interface OnTouchListener {
boolean onTouch(View v, MotionEvent event);
}
public void setOnTouchListener(OnTouchListener l) {
getListenerInfo().mOnTouchListener = l;
}
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
在结合上述一段代码可以看到,通过setOnTouchListener方法设置OnTouchListener以后,若是当前View处于可用状态,那么条件li != null && li.mOnTouchListener !=null && (mViewFlags & ENABLED_MASK) == ENABLED必然为true。这时候程序便会回调OnTouchListener中的onTouch方法,若是在onTouch方法中返回true,便不会在执行View的onTouchEvent方法。从这里我们能够看到,一旦设置了OnTouchListener,那么OnTouchListener的优先级要高于onTouchEvent。
有一点需要注意,在程序中设置了OnTouchListener以后,对于OnTouchListener中的onTouch的返回值并不代表View中的dispatchTouchEvent方法所返回的值。在onTouch方法返回true的时候,表示事件成功被当前View所消耗,这时候result被置为true并且不再执行onTouchEvent,所以dispatchTouchEvent也就返回true。可是一旦在onTouch方法中返回false。这时候便会调用onTouchEvent方法,如果事件被onTouchEvent成功处理,并返回true,result依然会被置为true,dispatchTouchEvent自然而然的也就返回true。
下面在进入View的onTouchEvent方法一探究竟。对于onTouchEvent方法里的内容比较多,在这里分段查看。
if ((viewFlags & ENABLED_MASK) == DISABLED) {
if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE);
}
在这里可以看出对于不可用的View,如果他们的一些点击事件可用的话,依然能够成功的消费事件,只是它不会为该事件做出响应。对于View的这些点击之间默认为不可用,但是对于不同的的View他们的默认值不一样。例如在ImageView中点击事件依然为不可用,但是在Button中点击事件为可用。当然如果手动为它们设置监听事件,那么这些监听事件都将会自动被设为可用状态。从如下源码中可以看出。
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
getListenerInfo().mOnClickListener = l;
}
public void setOnLongClickListener(@Nullable OnLongClickListener l) {
if (!isLongClickable()) {
setLongClickable(true);
}
getListenerInfo().mOnLongClickListener = l;
}
public void setOnContextClickListener(@Nullable OnContextClickListener l) {
if (!isContextClickable()) {
setContextClickable(true);
}
getListenerInfo().mOnContextClickListener = l;
}
下面接着看OnTouchEvent里面代码。
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
这里首先判断是否对事件设置了代理,如果对事件设置了代理,便会执行TouchDelegate的onTouchEvent方法。mTouchDelegate默认值为null,可以通过View的setTouchDelegate方法来设置代理。对于TouchDelegate在后续的文章中在进行详细分析,在这里就不在过多描述。
最后看一下View是如何处理事件的,对于接收的事件整个处理过程比较复杂,在这里就从宏观上来整体看一下它的处理机制。
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
(viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
switch (action) {
case MotionEvent.ACTION_UP:
......
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
......
break;
......
}
return true;
}
如果View的点击事件处于可用状态的话,便会对于这些事件进行处理,并且返回true。当一个事件序列完成以后调用performClick方法,下面看下这个performClick方法。
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
从上面代码中可以看出,如果我们设置了OnClickListener,便会调用它的onClick方法。从这一路下来我们可以看出对于View的onClick事件,在最后才会被调用,可见onClick的优先级是最低的。
总结
在这里对View的事件处理做一下总结。在ViewGroup将事件分发到View以后。在View里面通过OnTouchListener的onTouch和View中的onTouchEvent这两个方法对事件进行处理。对于onTouch方法是View提供给用户的,方便用户自己处理触摸事件,而onTouchEvent是Android系统自己实现的接口。若是用户设置了OnTouchListener,Android系统会首先调用OnTouchListener的onTouch方法。若是在onTouch方法中返回true,就不在执行View的onTouchEvent方法。只有在onTouch中返回了false才会执行onTouchEvent。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# Android事件分发机制
# View事件处理
# Android事件分发
# Android开发事件处理的代码如何写手摸手教程
# Android事件分发之View事件处理关键及示例分析
# Android XRecyclerView最简单的item点击事件处理
# 详解Android的两种事件处理机制
# Android 中 EventBus 的使用之多线程事件处理
# Android开发多手指触控事件处理
# 在这里
# 便会
# 可以看出
# 看一下
# 他们的
# 不可用
# 也就
# 才会
# 这时候
# 会对
# 就来
# 如何处理
# 这一
# 也不
# 将会
# 在这
# 设为
# 会在
# 它是
# 这也
相关文章:
宝塔新建站点报错如何解决?
宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?
小型网站建站如何选择虚拟主机?
视频网站制作教程,怎么样制作优酷网的小视频?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
实现点击下箭头变上箭头来回切换的两种方法【推荐】
建站之星安装后如何自定义网站颜色与字体?
广东企业建站网站优化与SEO营销核心策略指南
香港服务器网站搭建教程-电商部署、配置优化与安全稳定指南
如何在阿里云完成域名注册与建站?
如何配置FTP站点权限与安全设置?
如何用美橙互联一键搭建多站合一网站?
建站三合一如何选?哪家性价比更高?
网站制作公司排行榜,抖音怎样做个人官方网站
昆明网站制作哪家好,昆明公租房申请网上登录入口?
美食网站链接制作教程视频,哪个教做美食的网站比较专业点?
建站之星如何修改网站生成路径?
南阳网站制作公司推荐,小学电子版试卷去哪里找资源好?
Python多线程使用规范_线程安全解析【教程】
网站制作的步骤包括,正确网址格式怎么写?
高端建站三要素:定制模板、企业官网与响应式设计优化
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
教育培训网站制作流程,请问edu教育网站的域名怎么申请?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
jQuery 常见小例汇总
制作电商网页,电商供应链怎么做?
,有什么在线背英语单词效率比较高的网站?
北京网页设计制作网站有哪些,继续教育自动播放怎么设置?
制作网站的软件免费下载,免费制作app哪个平台好?
建站之星如何开启自定义404页面避免用户流失?
济南网站制作的价格,历城一职专官方网站?
,怎么在广州志愿者网站注册?
C++中引用和指针有什么区别?(代码说明)
小米网站链接制作教程,请问miui新增网页链接调用服务有什么用啊?
,购物网站怎么盈利呢?
建站之星CMS建站配置指南:模板选择与SEO优化技巧
建站之星ASP如何实现CMS高效搭建与安全管理?
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
山东网站制作公司有哪些,山东大源集团官网?
php8.4新语法match怎么用_php8.4match表达式替代switch【方法】
香港服务器WordPress建站指南:SEO优化与高效部署策略
赚钱网站制作软件,建一个网站怎样才能赚钱?是如何盈利的?
建站主机选哪种环境更利于SEO优化?
Bpmn 2.0的XML文件怎么画流程图
临沂网站制作企业,临沂第三中学官方网站?
如何通过虚拟主机空间快速建站?
网站制作培训多少钱一个月,网站优化seo培训课程有哪些?
IOS倒计时设置UIButton标题title的抖动问题
韩国服务器如何优化跨境访问实现高效连接?
建站之星云端配置指南:模板选择与SEO优化一键生成
*请认真填写需求信息,我们会在24小时内与您取得联系。