Android View的事件分发
来源:互联网 发布:淘宝上杰胜体育怎么样 编辑:程序博客网 时间:2024/05/16 17:27
- View的事件分发机制:
- 分析的对象
- MotionEvent: 表示点击事件, 例如Action_DOWN、Action_UP、Action_MOVE等
- 事件的传递过程:
- dispatchTouchEvent: 事件分发 (事件能否传递给当前View)
- onInterceptTouchEvent : 事件拦截(是否拦截事件)
- onTouchEvent : 处理点击事件
- 分析的对象
1、 产生一个Action_Down时,即产生了一个点击操作,事件由此开始,其顺序为 Activity -> Window -> View。最开始事件会在Activity的dispatchTouchEvent中进行事件的分发,实际的工作由Activity内部的Window完成。Window是一个抽象类,其唯一实现是PhoneWindow。在PhoneWindow中有一个内部类DecorView,而DecorView可以看成是我们当前界面的底层容器(也是我们setContentView设置的View的父容器)。在这,我们可以发现,事件会经过PhoneWindow -> DecorView传递到了顶级View,即setContentView设置的View。
下面看一张草图,以简单的形式描绘了一下大致的一个传递过程,包含了Activity层,ViewGroup层,View层。ViewGroup层是setContentView设置的View,View层是ViewGroup中的子View。
来捋一下上图中大致的流程,图中return super为父类的实现;false表示表示不消费事件;true表示消费事件。
《1》若在Activity层中的dispatchTouchEvent就return true(false),事件将不会再往下传递。
《2》事件传递到ViewGroup层中的dispatchTouchEvent时,若返回false,则事件会回传到父容器Activity层的onTouchEvent中消费。
反之,会传递到onInterceptTouchEvent,其默认为false,即不拦截事件,事件会传递给View层中的dispatchTouchEvent。若返回true时,表示拦截当前事件,直接会在ViewGroup层中的onTouchEvent决定是否消费此事件,返回true为消费,否者不消费,事件回传到父容器中的onTouchEvent。
《3》若View层中的dispatchTouchEvent可以接收事件,则由此再事件分发,若返回false,事件会回传到ViewGroup层中的onTouchEvent决定是否消费,这里再不消费,就会再回传到Activity层中的onTouchEvent消费。反之,再当前View层中消费事件。
注: onInterceptTouchEvent方法只属于ViewGroup。
2、 看一个简单的Demo,自定义两个布局文件,CustomViewR继承于RelativeLayout,CustomViewButton继承于AppCompatButton。实现相应的dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent。并且也在MainActivity重写dispatchTouchEvent和onTouchEvent方法。
MainActivity表示Acitvity层
public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent: ->"+"Activity dispatch DOWN" ); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent: ->"+"Activity onTouchEvent DOWN" ); break; } return super.onTouchEvent(event); }}
CustomViewR表示ViewGroup层
public class CustomViewR extends RelativeLayout {//省略构造方法 private static final String TAG = "CustomViewR"; @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent: ->"+"CustomR dispatch DOWN" ); break; } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "onInterceptTouchEvent: ->"+"CustomR onIntercept DOWN" ); break; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent: --->"+"CustomR onTouchEvent DOWN"); break; } return super.onTouchEvent(event); }}
CustomViewButton表示View层
public class CustomViewButton extends AppCompatButton {//省略构造方法 private static final String TAG = "CustomViewButton"; @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "dispatchTouchEvent: ->"+"CustomButton dispatch DOWN" ); break; } return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.e(TAG, "onTouchEvent: --->"+"CustomButton onTouchEvent DOWN" ); break; } return super.onTouchEvent(event); }}
<1>上述代码中默认返回父类的实现,那么看一下输出Log:
MainActivity: dispatchTouchEvent: ->Activity dispatch DOWNCustomViewR: dispatchTouchEvent: ->CustomR dispatch DOWNCustomViewR: onInterceptTouchEvent: ->CustomR onIntercept DOWNCustomViewButton: dispatchTouchEvent: ->CustomButton dispatch DOWNCustomViewButton: onTouchEvent: --->CustomButton onTouchEvent DOWN
可以看出,当以默认的父类的实现返回时,View的onTouchEvent会默认消耗事件,即返回true。
<2>还是以上述代码为例,当在View层的onTouchEvent中返回false,代码我就不再贴出来,看下输出日志:
MainActivity: dispatchTouchEvent: ->Activity dispatch DOWNCustomViewR: dispatchTouchEvent: ->CustomR dispatch DOWNCustomViewR: onInterceptTouchEvent: ->CustomR onIntercept DOWNCustomViewButton: dispatchTouchEvent: ->CustomButton dispatch DOWNCustomViewButton: onTouchEvent: --->CustomButton onTouchEvent DOWNCustomViewR: onTouchEvent: --->CustomR onTouchEvent DOWNMainActivity: onTouchEvent: ->Activity onTouchEvent DOWN
对比第一次的日志输出,可以明显的看出,后面多输出了两条数据,也就是说,在CustomViewButton中的onTouchEvent返回false,没有消费这次的点击事件,则回传给父容器中的onTouchEvent。
<3>再看下当我们在CustomViewR中的onInterceptTouchEvent中返回true,即拦截了当前事件。Log如下:
MainActivity: dispatchTouchEvent: ->Activity dispatch DOWNCustomViewR: dispatchTouchEvent: ->CustomR dispatch DOWNCustomViewR: onInterceptTouchEvent: ->CustomR onIntercept DOWNCustomViewR: onTouchEvent: --->CustomR onTouchEvent DOWNMainActivity: onTouchEvent: ->Activity onTouchEvent DOWN
上述代码可以看出,当onInterceptTouchEvent拦截了事件后,将不会再传递到下一层CustomViewButton中,而为什么又回传到了Activity 层的
onTouchEvent呢?是因为在ViewGrop层中的onTouchEvent 默认返回false,所以不消耗事件,把事件回传给了父容器。
总结:这一次View事件分发就写到这,结合图和代码的展示,相信这样看会看的比较明了。这里虽然只写了一个单一的Action_DOWN事件,但是View的分发机制中,一个事件产生后都会遵循刚才说的规则传递:Activity -> Window -> View。
注: 一个事件的完成,表示从手指点击屏幕开始,直到离开屏幕的过程,即Action_DOWN开始,中间可能会有很多个Action_MOVE,以Action_UP结束。
- Android View的事件分发
- Android View的事件分发
- Android View的事件分发
- android View的事件分发
- Android View的事件分发
- Android 事件分发机制解析之View的事件分发
- android事件分发机制 VIew的事件分发机制
- android 事件分发 View
- android View 事件分发
- android view 事件分发
- Android View事件分发
- android View事件分发
- android View 事件分发
- Android View 事件分发
- android view事件分发
- android中view的事件分发机制
- Android之View的事件分发机制
- Android View的事件分发机制
- this和currentThread的区别
- java(JDBC连接数据库)[完整版封装]
- (转)段永平:投资不怕集中,不是一般的集中而是绝对的集中
- Ubuntu16.04.1 升级内核
- 微信小程序欢迎界面的制作
- Android View的事件分发
- @synchronized 互斥锁
- IOS代码实现Hello World
- MSSQL附加数据库5120错误(拒绝访问)处理方法
- 为Linux-Centos用户添加sudu权限
- 51Nod-1379-索函数
- leetcode73. Set Matrix Zeroes
- JAVA的小方法
- 创建第一款iPhone应用程序