自定义控件之事件分发
来源:互联网 发布:现在做农村淘宝赚钱吗 编辑:程序博客网 时间:2024/04/27 19:09
android事件分发机制:
Android中与事件分发机制相关的方法有dispatchTouchEvent(MotionEvent ev),onInterceptTouchEvent(MotionEvent ev),onTouchEvent(MotionEvent event)。
**注意:**View对dispatchTouchEvent(MotionEvent ev)和onInterceptTouchEvent(MotionEvent ev)响应的前提是View可以向下传递事件,如果View已经是最小的控件了,那么它就没有dispatchTouchEvent(MotionEvent ev)和onInterceptTouchEvent(MotionEvent ev)了,只有onTouchEvent(MotionEvent event)。
public class TouchUtils { public static String getTouchAction(int actionId){ String action = null; switch (actionId){ case MotionEvent.ACTION_DOWN: action = "MotionEvent.ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: action = "MotionEvent.ACTION_MOVE"; break; case MotionEvent.ACTION_UP: action = "MotionEvent.ACTION_UP"; break; case MotionEvent.ACTION_CANCEL: action = "MotionEvent.ACTION_CANCEL"; break; default:break; } return action; }}
自定义控件LFather:
public class LFather extends LinearLayout { private static String TAG = "事件分发"; public LFather(Context context) { super(context); } public LFather(Context context, AttributeSet attrs) { super(context, attrs); } public LFather(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d(TAG,"LFather |dispatchTouchEvent -->"+ TouchUtils.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG,"LFather |onInterceptTouchEvent -->"+TouchUtils.getTouchAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.w(TAG,"LFather |onTouchEvent -->"+TouchUtils.getTouchAction(event.getAction())); return super.onTouchEvent(event); }}
自定义控件LChild:
public class LChild extends LinearLayout { private static String TAG = "事件分发"; public LChild(Context context) { super(context); } public LChild(Context context, AttributeSet attrs) { super(context, attrs); } public LChild(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d(TAG,"LChild |dispatchTouchEvent -->"+ TouchUtils.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev);// return true; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.e(TAG,"LChild |onInterceptTouchEvent -->"+TouchUtils.getTouchAction(ev.getAction())); return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.w(TAG,"LChild |onTouchEvent -->"+TouchUtils.getTouchAction(event.getAction())); return super.onTouchEvent(event); }}
主函数MainActivity:
public class MainActivity extends AppCompatActivity { private static String TAG = "事件分发"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onTouchEvent(MotionEvent event) { Log.w(TAG,"MainActivity |onTouchEvent -->"+ TouchUtils.getTouchAction(event.getAction())); return super.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d(TAG,"MainActivity |dispatchTouchEvent -->"+ TouchUtils.getTouchAction(ev.getAction())); return super.dispatchTouchEvent(ev); }}
布局:
<cn.centran.zx_event_distribution.view.LFather xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/rl" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" tools:context="cn.centran.zx_event_distribution.MainActivity"> <cn.centran.zx_event_distribution.view.LChild android:id="@+id/lc" android:layout_width="match_parent" android:layout_height="400dp" android:background="#88ff0000"></cn.centran.zx_event_distribution.view.LChild></cn.centran.zx_event_distribution.view.LFather>
效果:
事件分发机制分析:
事件分发:dispatchTouchEvent(MotionEvent ev):
当事件发生时,Activity的dispatchTouchEvent(MotionEvent ev)会将事件传递给最外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法,并由该 View 的 dispatchTouchEvent(MotionEvent ev) 方法对事件进行分发。dispatchTouchEvent 的事件分发逻辑如下:
- 如果返回true:表示事件给当前的View的dispatchTouchEvent进行消费,并停止向下分发。
如果返回false,那么有两种情况:
- 如果事件是Activity分发过来的,那么该事件就会返回给Activity的onTouchEvent进行处理
- 如果事件是外层父控件分发过来的,那么该事件就会返回给该控件的onTouchEvent进行处理
如果返回super.dispatchTouchEvent(ev),那么该事件是否需要拦截需要通过onInterceptTouchEvent(MotionEvent ev)返回值来判断。
案例1:
| MainActivity | LFather | LChild |
————- | ————- |——–
dispatchTouchEvent | super.dispatchTouchEvent(ev) |super.dispatchTouchEvent(ev)|super.dispatchTouchEvent(ev)
onInterceptTouchEvent | |super.onInterceptTouchEvent(ev)|super.onInterceptTouchEvent(ev)
onTouchEvent |super.onTouchEvent(event)|super.onTouchEvent(event)|super.onTouchEvent(event)
点击红色中心,运行效果:
分析:
点击事件传递给MainActivity的dispatchTouchEvent,因为它的返回值是super.onTouchEvent(event),所以它又将事件分给外层的LFather的dispatchTouchEvent,LFather的dispatchTouchEvent的返回值也是super.dispatchTouchEvent(ev),所以需要通过LFather的onInterceptTouchEvent的返回值来判断是否需要拦截,因为它的onInterceptTouchEvent返回值是super.onInterceptTouchEvent(ev),查看源码知道返回的是false,所以表示不拦截事件,事件向下传递给LChild的dispatchTouchEvent,因为它的返回值也是super.dispatchTouchEvent(ev),所以需要通过onInterceptTouchEvent来判断是否需要拦截,因为onInterceptTouchEvent的返回值也是系统默认的super.onInterceptTouchEvent(ev),所以不拦截该事件,因为LChild是最里层的控件了,所以事件无法向下传递了,那么它就会传递个LChild的onTouchEvent,但是onTouchEvent的返回值是系统默认的super.onTouchEvent(event),所以事件接着向上一级传递,再传递个它的上一层控件LFather的onTouchEvent,它的返回值也是系统默认的super.onTouchEvent(event),所以不拦截,接着传递给MainActivity的onTouchEvent,最后就是后续事件就会在MainActivity的dispatchTouchEvent的分发的时候直接分发给MainActivity的onTouchEvent,不会再向下传递了。
案例2:
| MainActivity | LFather | LChild |
————- | ————- |——–
dispatchTouchEvent | super.dispatchTouchEvent(ev) |true|super.dispatchTouchEvent(ev)
onInterceptTouchEvent | |super.onInterceptTouchEvent(ev)|super.onInterceptTouchEvent(ev)
onTouchEvent |super.onTouchEvent(event)|super.onTouchEvent(event)|super.onTouchEvent(event)
运行结果:
结果分析:
点击事件通过MainActivity的dispatchTouchEvent传递个外层的LFather的dispatchTouchEvent,因为它的返回值是true,表示事件被它消费掉,不会再传递了。后续事件也一样。
案例3:
| MainActivity | LFather | LChild |
————- | ————- |——–
dispatchTouchEvent | super.dispatchTouchEvent(ev) |super.dispatchTouchEvent(ev)|false
onInterceptTouchEvent | |super.onInterceptTouchEvent(ev)|super.onInterceptTouchEvent(ev)
onTouchEvent |super.onTouchEvent(event)|super.onTouchEvent(event)|super.onTouchEvent(event)
运行结果:
结果分析:
事件通过MainActivity的dispatchTouchEvent传递给外层的LFather的dispatchtouchEvent,因为它的返回值是super.dispatchTouchEvent(ev),然后需要通过onInterceptTouchEvent的返回值判断是否需要拦截该事件,又因为onInterceptTouchEvent的返回值是super.onInterceptTouchEvent(ev),表示不拦截,事件继续向下分发到LChild的dispatchTouchEvent上,因为它的返回值为false,表示事件不再向下分发了,同时也不对事件进行消费,那么就会将事件传递给它的上一层LFather的onTouchEvent处理,因为LFather的onTouchEvent的返回值是super.onTouchEvent(event),所以接着向上传递,一直到MainActivity的onTouchEvent上,后续的事件那么就会通过MainActivity的dispatchTouchEvent直接传递个MainActivity的onTouchEvent进行处理。
事件拦截:onInterceptTouchEvent(MotionEvent ev):
当dispatchTouchEvent的返回值是super.dispatchTouchEvent(ev)的时候,那么事件就会需要通过onInterceptTouchEvent的返回值来判断是否需要拦截该事件,这种情况有两种:
- 当返回值是true:表示拦截该事件,并将事件传递个它所在View的onTouchEvent来处理。
- 当返回值是false:表示不拦截该事件,并将事件传递给下一层的View的dispatchTouchEvent进行分发。注意返回值是super.onInterceptTouchEvent(ev),查看源码知道,就是返回false。
案例4:
| MainActivity | LFather | LChild |
————- | ————- |——–
dispatchTouchEvent | super.dispatchTouchEvent(ev) |super.dispatchTouchEvent(ev)|super.dispatchTouchEvent(ev)
onInterceptTouchEvent | |super.onInterceptTouchEvent(ev)|true
onTouchEvent |super.onTouchEvent(event)|super.onTouchEvent(event)|super.onTouchEvent(event)
运行结果:
结果分析:
事件通过MainActivity的dispatchTouchEvent分发传递给LFather的dispatchTouchEvent,因为LFather中的dispatchTouchEvent返回值是super.dispatchTouchEvent(ev),表示需要通过LFather中的onInterceptTouchEvent来判断是否需要拦截该事件,因为onInterceptTouchEvent的返回值是super.onInterceptTouchEvent(ev),表示不拦截该事件,事件被分发给LChild的dispatchToucEvent,因为LChild的dispatchToucEvent的返回值是super.dispatchTouchEvent(ev),所以需要LChild中的onInterceptTouchEvent返回值来判断是否需要拦截,因为它的返回值是true,表示拦截该事件,并将事件分给LChild中的onTouchEvent进行处理,但是onTouchEvent的返回值是super.onTouchEvent(event),表示没有对该事件进行处理,那么事件就会上传到上一层,最后MainActivity中的onTouchEvent进行处理,后续事件就会直接通过MainActivity的dispatchTouchEvent分发到MainActivity的onTouchEvent进行处理。
事件响应:onTouchEvent(MotionEvent event):
当事件传递到onTouchEvent,事件响应逻辑分为两种:
- 当返回值为true:表示事件在此被消耗。
- 当返回值为false:表示事件没有在此被消耗,那么事件就会继续向上传递,直到Activity中onTouchEvent。注意当返回值是super.onTouchEvent(event),查看源码知道它就相当于返回false。
案例5:
| MainActivity | LFather | LChild |
————- | ————- |——–
dispatchTouchEvent | super.dispatchTouchEvent(ev) |super.dispatchTouchEvent(ev)|super.dispatchTouchEvent(ev)
onInterceptTouchEvent | |super.onInterceptTouchEvent(ev)|true
onTouchEvent |super.onTouchEvent(event)|true|super.onTouchEvent(event)
运行结果:
结果分析:
当事件由MainActivity的dispatchTouchEvent分发给LFather的dispatchTouchEvent的时候,因为该dispatchTouchEvent的返回值为super.dispatchTouchEvent(ev),那么在LFather中需要查看onInterceptTouchEvent的返回值来判断是否需要拦截该事件,但是onInterceptTouchEvent的返回值为super.onInterceptTouchEvent(ev),表示不拦截该事件,那么事件就会继续向下传递给LChild的dispatchTouchEvent,因为该dispatchTouchEvent的返回值为super.dispatchTouchEvent(ev),那么在LChild中需要查看onInterceptTouchEvent的返回值来判断是否需要拦截该事件,但是onInterceptTouchEvent的返回值为true,表示拦截该事件,并把事件传递给LChild中onTouchEvent来进行处理,但是该onTouchEvent的返回值super.onTouchEvent(event),表示不处理,那么事件将向上传递给LFather的onTouchEvent,因为该onTouchEvent的返回值为true,表示拦截事件,那么事件在此被消耗,后续的事件则通过MainActivity的dispatchTouchEvent分发给LFather的dispatchTouchEvent,然后再将事件传递个LFather的onTouchEvent来处理。
- 自定义控件之事件分发
- Android自定义控件之触摸事件分发机制
- 属性动画、事件分发和自定义控件
- 【自定义控件】android事件分发机制
- 自定义控件(二) 从源码分析事件分发机制
- Swift自定义事件分发
- 安卓中的事件分发机制之View控件
- Android控件之View的事件分发机制探索
- 事件分发之扫描自定义注解实现观察者模式注册
- 自定义控件篇 第二章 输入事件(触摸滑动,Scroller,事件分发机制)
- 事件分发之View
- 事件分发之onInterceptTouchEvent
- 自定义view的事件分发
- 自定义viewgroup中的事件分发
- 自定义控件之事件回传
- 自定义控件之触摸事件的传递
- Android自定义控件系列九:从源码看Android触摸事件分发机制
- Android自定义控件系列九:从源码看Android触摸事件分发机制
- Application.mk 介绍
- CnetOS 64安装Tomcat85(从本地上传)
- swap影响gc的原因~~
- QT4中构建多线程的服务器and QT'Socket
- python问题集
- 自定义控件之事件分发
- SWJTU OJ 西安交通大学第十三届ACM程序设计决赛-题解
- 1. ATF(ARM Trusted firmware)完成启动流程
- 输出数组题
- 安装ORACLE出现注册OCX是出现OLE初始化错误或者OCX加载错误
- HDU-5874-Friends and Enemies
- 我就是懒的要命
- Java判断一个对象属性是否为空
- 30多条mysql数据库优化方法,千万级数据库记录查询轻松解决