Android中Touch事件的传递机制

由于之前对于android的事件传递机制不了解,今天正好不忙,赶紧抽出时间来理一下这方面的知识,本文结合demo,对android的事件传递机制进行分析。

在事件传递过程中,离不开以下三个方法:

1.dispatchTouchEvent 分发touchEvent,返回值为true时表示TouchEvent被当前View处理,事件不会向下层传递(包括后续的onInterceptTouchEvent和onTouchEvent),

dispatchTouchEvent会收到后续的ACTION_MOVE和ACTION_UP事件

2.onInterceptTouchEvent 拦截touchEvent,返回true时表示当前View拦截了touchEvent,然后把事件交给当前View的onTouchEvent处理

3.onTouchEvent 处理TouchEvent,返回true时表示当前View消费了此事件,只有消费了前一个事件后才能收到后续事件。

为了弄清楚android在各层view的事件传递,我写了一个小demo来分析Activity,ViewGroup,View之间的事件传递。

首先来看一下代码,一个自定义View,画了一个矩形,在dispatchTouchEvent,onTouchEvent中加入日志方便解析。

 1 public class DrawRectView extends View {
 2
 3     private Paint mPaint;
 4
 5     public DrawRectView(Context context) {
 6         super(context);
 7         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 8     }
 9
10     public DrawRectView(Context context, AttributeSet set) {
11         super(context, set);
12         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
13     }
14
15     @Override
16     public boolean dispatchTouchEvent(MotionEvent event) {
17         Log.v(LogUtils.TAG, "DrawRectView dispatchTouchEvent action=" + event.getAction());
18         return super.dispatchTouchEvent(event);
19     }
20
21
22     @Override
23     protected void onDraw(Canvas canvas) {
24         super.onDraw(canvas);
25         mPaint.setColor(Color.YELLOW);
26         canvas.drawRect(0, 0, 300, 300, mPaint);
27     }
28
29     @Override
30     public boolean onTouchEvent(MotionEvent event) {
31         Log.v(LogUtils.TAG, "DrawRectView onTouchEvent action=" + event.getAction());
32         return super.onTouchEvent(event);
33     }
34 }

自定义Layout,同样在相关的TouchEvent方法中加入log

 1 public class MyLayout extends RelativeLayout {
 2
 3     public MyLayout(Context context, AttributeSet attrs) {
 4         super(context, attrs);
 5     }
 6
 7     @Override
 8     public boolean dispatchTouchEvent(MotionEvent ev) {
 9         Log.v(LogUtils.TAG, "MyLayout dispatchTouchEvent action=" + ev.getAction());
10         return super.dispatchTouchEvent(ev);
11     }
12
13     @Override
14     public boolean onInterceptTouchEvent(MotionEvent ev) {
15         Log.v(LogUtils.TAG, "MyLayout onInterceptTouchEvent action=" + ev.getAction());
16         return super.onInterceptTouchEvent(ev);
17     }
18
19     @Override
20     public boolean onTouchEvent(MotionEvent event) {
21         Log.v(LogUtils.TAG, "MyLayout onTouchEvent event=" + event.getAction());
22         return super.onTouchEvent(event);
23     }

接下来是Activity与activity的布局

 1 public class TouchTestActivity extends Activity {
 2
 3     private DrawRectView mDrawRectView;
 4
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.touch_test_activity);
 9
10         mDrawRectView = (DrawRectView) findViewById(R.id.draw_rect_view);
11         mDrawRectView.setOnTouchListener(new OnTouchListener() {
12             @Override
13             public boolean onTouch(View v, MotionEvent event) {
14                 Log.v(LogUtils.TAG, "mDrawRectView OnTouchListener action=" + event.getAction());
15                 return false;
16             }
17         });
18     }
19
20     @Override
21     public boolean dispatchTouchEvent(MotionEvent ev) {
22         Log.v(LogUtils.TAG, "TouchTestActivity dispatchTouchEvent action=" + ev.getAction());
23         return super.dispatchTouchEvent(ev);
24     }
25
26     @Override
27     public boolean onTouchEvent(MotionEvent event) {
28         Log.v(LogUtils.TAG, "TouchTestActivity onTouchEvent action=" + event.getAction());
29         return super.onTouchEvent(event);
30     }
31 }
 1 <com.yangy.test.custom_view.MyLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent" >
 4
 5     <com.yangy.test.custom_view.DrawRectView
 6         android:id="@+id/draw_rect_view"
 7         android:layout_width="300dp"
 8         android:layout_height="300dp"
 9         android:layout_centerInParent="true" />
10
11 </com.yangy.test.custom_view.MyLayout>

当我们按下矩形DrawRectView时,可以看到打印的log信息如下,Android Touch事件自上到下传递,Activity-->ViewGroup-->View

11-24 15:19:40.659: V/--DEBUG--(32570): TouchTestActivity dispatchTouchEvent action=ACTION_DOWN
11-24 15:19:40.659: V/--DEBUG--(32570): MyLayout dispatchTouchEvent action=ACTION_DOWN
11-24 15:19:40.659: V/--DEBUG--(32570): MyLayout onInterceptTouchEvent action=ACTION_DOWN
11-24 15:19:40.659: V/--DEBUG--(32570): DrawRectView dispatchTouchEvent action=ACTION_DOWN
11-24 15:19:40.659: V/--DEBUG--(32570): mDrawRectView OnTouchListener action=ACTION_DOWN
11-24 15:19:40.669: V/--DEBUG--(32570): DrawRectView onTouchEvent action=ACTION_DOWN
11-24 15:19:40.669: V/--DEBUG--(32570): MyLayout onTouchEvent event=ACTION_DOWN
11-24 15:19:40.669: V/--DEBUG--(32570): TouchTestActivity onTouchEvent action=ACTION_DOWN
11-24 15:19:40.689: V/--DEBUG--(32570): TouchTestActivity dispatchTouchEvent action=ACTION_UP
11-24 15:19:40.689: V/--DEBUG--(32570): TouchTestActivity onTouchEvent action=ACTION_UP

根据log信息,我们也就知道了整个View的事件传递流程,可用下图表示,这里值得注意的是没有任何View消耗掉ACTION_DOWN事件,

所以后续的ACTION_MOVE和ACTION_UP事件并不会向下传递了,这个从log中也可看出。

这时把DrawRectView的onTouchEvent方法返回true,则会出现什么结果呢,接着看log

11-24 16:04:03.159: V/--DEBUG--(3037): TouchTestActivity dispatchTouchEvent action=ACTION_DOWN
11-24 16:04:03.159: V/--DEBUG--(3037): MyLayout dispatchTouchEvent action=ACTION_DOWN
11-24 16:04:03.159: V/--DEBUG--(3037): MyLayout onInterceptTouchEvent action=ACTION_DOWN
11-24 16:04:03.159: V/--DEBUG--(3037): DrawRectView dispatchTouchEvent action=ACTION_DOWN
11-24 16:04:03.159: V/--DEBUG--(3037): mDrawRectView OnTouchListener action=ACTION_DOWN
11-24 16:04:03.159: V/--DEBUG--(3037): DrawRectView onTouchEvent action=ACTION_DOWN

11-24 16:04:03.219: V/--DEBUG--(3037): TouchTestActivity dispatchTouchEvent action=ACTION_MOVE
11-24 16:04:03.219: V/--DEBUG--(3037): MyLayout dispatchTouchEvent action=ACTION_MOVE
11-24 16:04:03.219: V/--DEBUG--(3037): MyLayout onInterceptTouchEvent action=ACTION_MOVE
11-24 16:04:03.219: V/--DEBUG--(3037): DrawRectView dispatchTouchEvent action=ACTION_MOVE
11-24 16:04:03.219: V/--DEBUG--(3037): mDrawRectView OnTouchListener action=ACTION_MOVE
11-24 16:04:03.219: V/--DEBUG--(3037): DrawRectView onTouchEvent action=ACTION_MOVE

11-24 16:04:03.249: V/--DEBUG--(3037): TouchTestActivity dispatchTouchEvent action=ACTION_UP
11-24 16:04:03.249: V/--DEBUG--(3037): MyLayout dispatchTouchEvent action=ACTION_UP
11-24 16:04:03.249: V/--DEBUG--(3037): MyLayout onInterceptTouchEvent action=ACTION_UP
11-24 16:04:03.249: V/--DEBUG--(3037): DrawRectView dispatchTouchEvent action=ACTION_UP
11-24 16:04:03.249: V/--DEBUG--(3037): mDrawRectView OnTouchListener action=ACTION_UP
11-24 16:04:03.249: V/--DEBUG--(3037): DrawRectView onTouchEvent action=ACTION_UP

看来DrawRectView的onTouchEvent方法消费掉ACTION_DOWN事件后,ACTION_MOVE与ACTION_UP都传递过来了,而因为消费了事件,所以onTouchEvent 并不会向上传递

如果在ViewGroup中拦截了TouchEvent事件又会怎么样呢,由下图来说明:

经过本文的说明后,相信你对于android的事件传递机制更了解了吧。

时间: 2024-10-05 00:15:52

Android中Touch事件的传递机制的相关文章

Android中Touch事件传递总结

TouchEvent TouchEvent 分三种事件:down.move.up. 其中move事件在一个操作中(这里说的一个操作就是用户与屏幕的交互,即由down到up的动作序列)可能会发生多次. 但是,我们认为一个动作序列会包含以上三种事件,因此,在事件处理中就是要处理好这个过程,而最重要的就是down事件,这是一个动作序列的起始,没有down谈不上后面的事件了. 所以,我们把消耗down事件的类当做是这个动作序列的最终载体. 如果Down事件不归你处理,那这个动作序列的move,up也不归

Touch事件的传递机制

本文主要从源代码的角度讲解view以及viewgroup的事件传递机制. ViewGroup的dispatchTouchEvent方法: Private TouchTarget firstTouchTarget; Public Boolean dispatchTouchEvent(MotionEvent ev){ 先进行安全检查,看看当前window有没有遮挡,如果没有继续 if(action==ACTION_DOWN){ 清理上次的TouchTargets的状态,避免程序切换和ANR的时候会抛

[学习总结]4、Android的ViewGroup中事件的传递机制(一)

本文主要针对dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三个方法,通过简单的例子来简单的介绍下. 根据字面意思的理解,dispatchTouchEvent分发触摸事件,onInterceptTouchEvent拦截触摸事件,onTouchEvent触摸事件.正如它们各自的字面意思,下面简单的列出各自的作用和用法. 1.dispatchTouchEvent作用:决定事件是否由onInterceptTouchEvent来拦截处理. 返回s

android中的事件传递和处理机制

一直以来,都被android中的事件传递和处理机制深深的困扰!今天特意来好好的探讨一下.现在的感觉是,只要你理解到位,其实事件的 传递和处理机制并没有想象中的那么难.总之,不要自己打击自己,要相信自己能掌握这块知识.好了,下面是我今天的收获,希望也 能对你有一点帮助. 一.拟人化来理解android中的事件机制 其实android中的事件传递与处理机制跟我们生活中的事件处理是一样的.这里有一个生活中的例子,很能说明这个问题.阐述如下: 你是一个公司的员工,你的上头有一个主管,主管上头呢还有一个经

[学习总结]5、Android的ViewGroup中事件的传递机制(二)

下面是第一篇的连接 Android的ViewGroup中事件的传递机制(一) 关于onInterceptTouchEvent和onTouchEvent的详细解释. 1 public class MainActivity extends Activity { 2 Group1 group1; 3 Group2 group2; 4 MyTextView myTv; 5 6 /** Called when the activity is first created. */ 7 @Override 8

Android中的事件传递机制

Android源码版本:API Level 19(Android 4.4) Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都由如下三个部分作为基础: 按下(ACTION_DOWN) 移动(ACTION_MOVE) 抬起(ACTION_UP) 所有的操作事件首先必须执行的是按下操作(ACTIONDOWN),之后所有的操作都是以按下操作作为前提,当按

android自定义控件系列教程-----touch事件的传递

前沿: 很久没有写过博客了,因为工作的原因很少有时间写东西了,最近想写一个UI系列的博客,因为我发现这一系列的都很少,而且没有那么系统,这里我想以我自己的观点来阐述一下如何自定义android 控件系列. 自定义控件阐述: 在我的理解里面自定义控件,需要了解到touch事件的传递.分发.拦截机制,Scroller类的运用,andorid 视图的理解,ViewGroup的熟悉,因为我们绝大多的控件都是继承自ViewGroup,还有就是要学会布局测量等. Touch事件的传递 首先我们要了解在and

Android——View、ViewGroup事件(Touch事件)处理机制总结

Android中的事件 Touch事件,四种状态: ACTION_DOWN     -->   表示按下了屏幕,一个事件必然从ACTION_DOWN开始 ACTION_MOVE      -->   表示移动手势 ACTION_UP            -->  表示离开屏幕 ACTION_CANCEL  -->   表示取消手势,一般由程序产生,不会由用户产生 一个ACTION_DOWN, n个ACTION_MOVE,1个ACTION_UP,就构成了Android中众多的事件.

Android中的事件分发机制——ViewGroup的事件分发

综述 Android中的事件分发机制也就是View与ViewGroup的对事件的分发与处理.在ViewGroup的内部包含了许多View,而ViewGroup继承自View,所以ViewGroup本身也是一个View.对于事件可以通过ViewGroup下发到它的子View并交由子View进行处理,而ViewGroup本身也能够对事件做出处理.下面就来详细分析一下ViewGroup对时间的分发处理. MotionEvent 当手指接触到屏幕以后,所产生的一系列的事件中,都是由以下三种事件类型组成.