对两个事件分发案例的探究
来源:互联网 发布:qq语音软件下载 编辑:程序博客网 时间:2024/06/10 21:15
在开发中,遇到两个事件分发方面的应用案例,实际运行与我的预期不符。特意做了实验,探究原因,现记录如下,以备日后查阅。
- 案例现象
- 原因探究
- AppCompatEditText
- SwitchCompat
- 总结
案例现象
抽象后的代码:
Activity:
findViewById(R.id.tv).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "textview onTouchED"); return false; } }); findViewById(R.id.edittext).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "edittext onTouchED"); return false; } }); findViewById(R.id.rootview).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d(TAG, "rootview onTouchED"); return false; } });
xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootview" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:background="@color/colorAccent" android:text="xxxxxx" android:textColor="@color/colorPrimaryDark" android:textSize="20sp" /> <android.support.v7.widget.AppCompatEditText android:id="@+id/edittext" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" /> <android.support.v7.widget.SwitchCompat android:id="@+id/switchBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" /></LinearLayout>
父 View 是 LinearLayout,有三个子 View:TextView、AppCompatEditText 和 SwitchCompat。除了 SwitchCompat,其余三个都绑定了 OnTouchListener,而且 onTouch() 方法返回 false。
运行 demo,依次点击上述控件,查看结果并得出下表:
rootview onTouchED textview onTouchED
rootview onTouchED 是 AppCompatEditText textview onTouchED
rootview onTouchED edittext onTouchED
edittext onTouchED 否 SwitchCompat rootview onTouchED 否
预期结果基于以下原理:
子 View 上绑定了 OnTouchListener,而且返回 false,表明其不消费该事件,如果父 View 上有 OnTouchListener,那父 View 会消费该事件;如果子 View 上没有绑定 OnTouchListener,那么子 View 不会消费 OnTouch 事件,交由父 View 消费。
从表格可知,只有 TextView 的行为符合预期。AppCompatEditText 有两个地方与预期不符:
- 父 View 没有消费 OnTouch 事件;
- AppCompatEditText 消费了两次 OnTouch 事件(打印出两次);
对于 SwitchCompat,根据预期,由于其并未绑定 OnTouchListener,被点击时应该未消费该事件,转而由其父 View 消费,应该打印出“rootview onTouchED”,然而实际并没有。
原因探究
AppCompatEditText
对于 AppCompatEditText,通过单步调试源代码发现:
第一,AppCompatEditText#dispatchTouchEvent() 返回 true,TextView(android-25)第 8485 行:
if (mMovement != null) { handled |= mMovement.onTouchEvent(this, (Spannable) mText, event); }
即,虽然我们在 OnTouchListener#onTouch() 返回了 false,但是 AppCompatEditText 实际上消费了该事件。
实际上,即使我们不对 AppCompatEditText 绑定 OnTouchListener,其 dispatchTouchEvent() 依旧返回 true,依然消费 DOWN 和 UP 事件。我推测控件消费这些事件用于乎起软键盘和输入框内文本选择。
第二,两次打印动作都是在 View#dispatchTouchEvent() 方法中进行的,分别对应 ACTION_DOWN 和 ACTION_UP ,第 10017 行:
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && li.mOnTouchListener.onTouch(this, event)) { result = true; }
这个故事告诉我们,我们预期的结果仅对那些没有绑定各种 Listener 以及没有复杂效果的控件有效,对于 EditText 以及 CompoundButton 这种自带特效的控件,不一定适用。还有一点,对于 AppCompatEditText,不仅只有 ACTION_DOWN 会触发其 OnTouchListener#onTouch(),ACTION_UP 也会触发。
SwitchCompat
单步调试发现,SwitchCompat 也消费了 DOWN 和 UP 事件,关键代码在 View 的 11181 行:
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) { switch (action) { case MotionEvent.ACTION_UP:// more code
此时,只有 (viewFlags & CLICKABLE) == CLICKABLE 成立,只要进入该 if 语句,就会返回 true。
既然消费了 DOWN 和 UP 事件,父 view 就不再消费了,这与实际结果相符。
总结
AppCompatEditText 和 SwitchCompat 这两个控件,有一个共同点,就是都是继承自 TextView。
这两个控件自身代码比较简单,都没有对 dispatchTouchEvent() 和 onTouchEvent() 方法进行重写,事件分发相关的逻辑都集中在 TextView 中。
TextView 对事件分发逻辑的处理相当复杂,具体问题当具体分析,不能用简单的通过是否显式绑定事件来做推断。
单步调试过程中绘出的视图树:
- 对两个事件分发案例的探究
- 探究View的事件分发
- android touch事件分发机制的探究
- 对事件分发的探讨
- Android事件分发机制探究
- TextView ClickableSpan 事件分发的两个坑
- TextView ClickableSpan 事件分发的两个坑
- 对view事件分发的理解
- android事件分发和案例
- Android事件分发机制源码剖析(1)——Activity对点击事件的分发过程
- Android事件分发机制源码剖析(2)—顶层View对点击事件的分发过程
- Android 开发艺术探究V第三章之view的事件分发机制
- Android开发之onTouch事件的分发拦截消费机制探究学习
- 对android中事件的分发的理解
- 对属性动画和事件分发机制的一些理解
- Android 关于setOnclickListener 对事件分发的影响
- 对Android view/viewgroup事件分发的理解
- ViewGroup对触摸事件的分发响应过程
- csdn中如何转载文章
- php 设计模式(抽象工厂)
- 神经网络
- Linux 用户切换、修改用户名、修改密码
- tcp三次握手
- 对两个事件分发案例的探究
- 解决:make:cc 命令未找到的解决方法
- Struts2系列之配置文件
- 为按钮连续点击设置时间间隔
- Android数据库的使用
- SparkSQL的原理以及架构
- mysql索引结构B+Tree结构
- bzoj1137 [POI2009]Wsp 岛屿 半平面交
- Activity创建时布局文件的实现原理