• 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的事件传递机制更了解了吧。

  • 相关阅读:
    软考收获
    寻找她(指令寻址)——(软考六)
    算法探究——(软考四)
    Shell排序——软考(五)
    Java String类源码
    Java 抽象类详解
    Spring IOC Container
    Tomcat的架构
    Spring与Web框架(例如Spring MVC)漫谈——关于Spring对于多个Web框架的支持
    HTML form表单中action的正确写法
  • 原文地址:https://www.cnblogs.com/virtual-young/p/4118890.html
Copyright © 2020-2023  润新知