Android事件处理机制
Android事件处理机制更准确的说应该叫 “Android事件分发、拦截、处理机制”。这里主要是针对Android中dispatchTouchEvent(分发TouchEvent), onInterceptTouchEvent(拦截TouchEvent), onTouchEvent(处理TouchEvent)事件的理解.
首先我们来认识下dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent事件.
dispatchTouchEvent用于决定事件是否分发,当TouchEvent事件发生时,最先到达顶层Activity的dispatchTouchEvent方法,返回ture或false时事件被自身消费处理,返回super.dispatchTouchEvent(ev)(后面简称super)传递给下一层级dispatchTouchEvent方法处理.
onInterceptTouchEvent用于决定事件是否继续向下传递返回false或super时事件会传递给子View,返回值为true时事件不会继续传递给子View,事件将交给当前ViewGroup的onTouchEvent()处理,这就是所谓的Intercept(拦截)。
onTouchEvent用于处理事件(传递方向是从子View->父View),返回值决定当前控件是否消费(处理)了这个事件。返回值为true表示处理了当前事件,父View的OnTouchEvent事件将不会执行,返回值为false或super表示不处理当前事件交给父View的OnTouchEvent事件处理。
注:对于当前事件理解: 一次点击操作可能包含三个事件,按下事件(Down),移动事件(Move),弹起事件(up).
对于ACTION_DOWN事件,返回true,表示我想要处理后续事件;返回false,表示不关心此事件,并返回由父类进行处理。
特别注意ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN,如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。
我们看下示例:
布局如下
<?xml version="1.0" encoding="utf-8"?> <com.scxh.android1502.event.RootLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.scxh.android1502.event.TwotLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.scxh.android1502.event.ChildTextView android:id="@+id/event_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="android事件处理机制" /> </com.scxh.android1502.event.TwotLayout> </com.scxh.android1502.event.RootLayout>
测试代码
public class RootLayout extends LinearLayout { public RootLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Logs.d("RootLayout onInterceptTouchEvent >>>>>>>"); return false; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: Logs.i("RootLayout onTouchEvent 事件 ACTION_UP>>>>>>>>"); break; case MotionEvent.ACTION_MOVE: Logs.v("RootLayout onTouchEvent 事件 ACTION_MOVE>>>>>>>>"); break; case MotionEvent.ACTION_DOWN: Logs.d("RootLayout onTouchEvent 事件 ACTION_DOWN>>>>>>>>"); break; } return true; } }
public class TwotLayout extends LinearLayout { public TwotLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Logs.i("TwotLayout onInterceptTouchEvent >>>>>>>"); return false; } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: Logs.i("TwotLayout onTouchEvent 事件 ACTION_UP>>>>>>>>"); break; case MotionEvent.ACTION_MOVE: Logs.v("TwotLayout onTouchEvent 事件 ACTION_MOVE>>>>>>>>"); break; case MotionEvent.ACTION_DOWN: Logs.d("TwotLayout onTouchEvent 事件 ACTION_DOWN>>>>>>>>"); break; } return false; } }
public class ChildTextView extends TextView { public ChildTextView(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: Logs.i("ChildTextView onTouchEvent 事件 ACTION_UP>>>>>>>>"); break; case MotionEvent.ACTION_MOVE: Logs.v("ChildTextView onTouchEvent 事件 ACTION_MOVE>>>>>>>>"); break; case MotionEvent.ACTION_DOWN: Logs.d("ChildTextView onTouchEvent 事件 ACTION_DOWN>>>>>>>>"); break; } return true; } }
1. 当RootLayout,TwoLayout的onInterceptTouchEvent事件返回false也就是不拦截且ChildTextView的onTouchEvent事件返回true消耗第一个Action_Down事件执行情况为:
2.当RootLayout,TwoLayout的onInterceptTouchEvent事件返回false也就是不拦截且ChildTextView的onTouchEvent事件返回false不消耗第一个Action_Down事件执行情况为:
事件传输机制更详细理解推荐kelin写的这编文章,http://www.jianshu.com/p/e99b5e8bd67b
这里贴张图.
参考
细说Android事件传递机制(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)
Android-onInterceptTouchEvent()和onTouchEvent()总结
Android中dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent的理解
转载请注明来源:Android事件处理机制