`
vssupermadman
  • 浏览: 23062 次
社区版块
存档分类
最新评论

MotionEvent事件在onInterceptTouchEvent()、onTouchEvent()中的传递顺序

阅读更多


onInterceptTouchEvent和onTouchEvent调用时序

onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截,Android这么设计的想法也很好理解,由于ViewGroup会包含若干childView,因此需要能够统一监控各种touch事件的机会,因此纯粹的不能包含子view的控件是没有这个方法的,如LinearLayout就有,TextView就没有。

onInterceptTouchEvent()使用也很简单,如果在ViewGroup里覆写了该方法,那么就可以对各种touch事件加以拦截。但是如何拦截,是否所有的touch事件都需要拦截则是比较复杂的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各个childView间的传递机制完全取决于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,针对down事件处理的返回值直接影响到后续move和up事件的接收和传递。

关于返回值的问题,基本规则很清楚,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

SDK给出的说明如下:

·  You will receive the down event here.

·  The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.

·  For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().

·  If you return true from here, you will not receive any following events: the target view will receive the same event but with the action ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.



由于onInterceptTouchEvent()的机制比较复杂,上面的说明写的也比较复杂,总结一下,基本的规则是:

1.       down事件首先会传递到onInterceptTouchEvent()方法

2.       如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。

3.       如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

4.       如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

5.       如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。



下面用一个简单的实验说明上述复杂的规则。视图自底向上共3层,其中LayoutView1和LayoutView2就是LinearLayout, MyTextView就是TextView:

对应的xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>

<com.touchstudy.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent" >

    <com.touchstudy.LayoutView2

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        android:gravity="center">

       <com.touchstudy.MyTextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:id="@+id/tv"

            android:text="AB"

            android:textSize="40sp"

            android:textStyle="bold"

            android:background="#FFFFFF"

            android:textColor="#0000FF"/>

   </com.touchstudy.LayoutView2>

</com.touchstudy.LayoutView1>



下面看具体情况:

1.       onInterceptTouchEvent()处理down事件均返回false,onTouchEvent()处理事件均返回true

------------------------------------------------------------------------------------------------------------------------------

04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_DOWN

04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_DOWN

04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN

04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_MOVE

04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_MOVE

04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE

…… //省略过多的ACTION_MOVE

04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_UP

04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_UP

04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP

------------------------------------------------------------------------------------------------------------------------------

这是最常见的情况,onInterceptTouchEvent并没有做任何改变事件传递时序的操作,效果上和没有覆写该方法是一样的。可以看到,各种事件的传递本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false时,LayoutView1和LayoutView2的onTouchEvent并不会收到事件,而是最终传递给了MyTextView。



2.     LayoutView1的onInterceptTouchEvent()处理down事件返回true,

MyTextView的onTouchEvent()处理事件返回true

------------------------------------------------------------------------------------------------------------------------------

04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEvent action:ACTION_DOWN

04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN

04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE

04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE

…… //省略过多的ACTION_MOVE

04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP

------------------------------------------------------------------------------------------------------------------------------

从Log可以看到,由于LayoutView1在拦截第一次down事件时return true,所以后续的事件(包括第一次的down)将由LayoutView1本身处理,事件不再传递下去。



3.       LayoutView1,LayoutView2的onInterceptTouchEvent()处理down事件返回false,

MyTextView的onTouchEvent()处理事件返回false

LayoutView2的onTouchEvent()处理事件返回true

----------------------------------------------------------------------------------------------------------------------------

04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN

04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEvent action:ACTION_DOWN

04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN

04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN

04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE

04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE

04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE

04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE

…… //省略过多的ACTION_MOVE

04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_UP

04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP

----------------------------------------------------------------------------------------------------------------------------

可以看到,由于MyTextView在onTouchEvent()中return false,down事件被传递给其父view,即LayoutView2的onTouchEvent()方法处理,由于在LayoutView2的onTouchEvent()中return true,所以down事件传递并没有上传到LayoutView1。注意,后续的move和up事件均被传递给LayoutView2的onTouchEvent()处理,而没有传递给MyTextView。



----------------------------------------------------------------------------------------------------------------

应大家的要求,我把源代码贴上,其实很简单,就是基础文件,主要是用来观察事件的传递。



主Activity: InterceptTouchStudyActivity.java:



public class InterceptTouchStudyActivity extends Activity {

    static final String TAG = "ITSActivity";

    TextView tv;

  

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.layers_touch_pass_test);

     }

}




      LayoutView1.java:


      public class LayoutView1 extends LinearLayout {

     private final String TAG = "LayoutView1";

       public LayoutView1(Context context, AttributeSet attrs) {

         super(context, attrs);

         Log.d(TAG,TAG);

     }



     @Override

     public boolean onInterceptTouchEvent(MotionEvent ev) {

         int action = ev.getAction();

         switch(action){

         case MotionEvent.ACTION_DOWN:

              Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");

//            return true;

              break;

         case MotionEvent.ACTION_MOVE:

              Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");

              break;

         case MotionEvent.ACTION_UP:

              Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");

              break;

         case MotionEvent.ACTION_CANCEL:

              Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");

              break;

         }

       

         return false;

     }



     @Override

     public boolean onTouchEvent(MotionEvent ev) {

         int action = ev.getAction();

         switch(action){

         case MotionEvent.ACTION_DOWN:

              Log.d(TAG,"onTouchEvent action:ACTION_DOWN");

              break;

         case MotionEvent.ACTION_MOVE:

              Log.d(TAG,"onTouchEvent action:ACTION_MOVE");

              break;

         case MotionEvent.ACTION_UP:

              Log.d(TAG,"onTouchEvent action:ACTION_UP");

              break;

         case MotionEvent.ACTION_CANCEL:

              Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");

              break;

         }

       

         return true;

     }



     @Override

     protected void onLayout(boolean changed, int l, int t, int r, int b) {

         // TODO Auto-generated method stub

         super.onLayout(changed, l, t, r, b);

     }



     @Override

     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

         // TODO Auto-generated method stub

         super.onMeasure(widthMeasureSpec, heightMeasureSpec);

     }

}


LayoutView2.java:



public class LayoutView2 extends LinearLayout {

    private final String TAG = "LayoutView2";

  

    public LayoutView2(Context context, AttributeSet attrs) {

       super(context, attrs);

       Log.d(TAG,TAG);

    }



    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

       int action = ev.getAction();

       switch(action){

       case MotionEvent.ACTION_DOWN:

           Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");

           break;

       case MotionEvent.ACTION_MOVE:

           Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");

           break;

       case MotionEvent.ACTION_UP:

           Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");

           break;

       case MotionEvent.ACTION_CANCEL:

           Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");

           break;

       }

     

       return false;

    }



    @Override

    public boolean onTouchEvent(MotionEvent ev) {

       int action = ev.getAction();

       switch(action){

       case MotionEvent.ACTION_DOWN:

           Log.d(TAG,"onTouchEvent action:ACTION_DOWN");

           break;

       case MotionEvent.ACTION_MOVE:

           Log.d(TAG,"onTouchEvent action:ACTION_MOVE");

           break;

       case MotionEvent.ACTION_UP:

           Log.d(TAG,"onTouchEvent action:ACTION_UP");

           break;

       case MotionEvent.ACTION_CANCEL:

           Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");

           break;

       }

     

       return true;

    }

}


MyTextView.java:

public class MyTextView extends TextView {

    private final String TAG = "MyTextView";

  

    public MyTextView(Context context, AttributeSet attrs) {

       super(context, attrs);

       Log.d(TAG,TAG);

    }



    @Override

    public boolean onTouchEvent(MotionEvent ev) {

       int action = ev.getAction();

       switch(action){

       case MotionEvent.ACTION_DOWN:

           Log.d(TAG,"onTouchEvent action:ACTION_DOWN");

           break;

       case MotionEvent.ACTION_MOVE:

           Log.d(TAG,"onTouchEvent action:ACTION_MOVE");

           break;

       case MotionEvent.ACTION_UP:

           Log.d(TAG,"onTouchEvent action:ACTION_UP");

           break;

       case MotionEvent.ACTION_CANCEL:

           Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");

           break;

       }

     

       return false;

    }

  

    public void onClick(View v) {

       Log.d(TAG, "onClick");

    }

  

    public boolean onLongClick(View v) {

       Log.d(TAG, "onLongClick");

       return false;

    }

}
分享到:
评论

相关推荐

    onTouchEvent 、onInterceptTouchEvent的顺序~

    在博客《onTouchEvent 、onInterceptTouchEvent的顺序》中,作者可能详细解释了这两个方法在实际应用中的操作流程: 1. **默认行为**: 当用户触摸屏幕时,事件首先由父视图的 `dispatchTouchEvent` 处理,如果父...

    onInterceptTouchEvent和onTouchEvent使用demo

    如果在某个父View中`onInterceptTouchEvent`返回`true`,则表示该父View想要拦截并处理这个事件,后续的触摸事件将不再传递给子View。默认情况下,`onInterceptTouchEvent`返回`false`,表示不拦截事件,事件将继续...

    onInterceptTouchEvent和onTouchEvent调用关系详解

    这个事件会沿着View树自上而下进行分发,首先是父View,然后是子View,直到某个View消费掉事件或者事件传递回父View。 `onInterceptTouchEvent`是父View( ViewGroup)决定是否拦截子View事件的入口。当一个...

    View的onInterceptTouchEvent(MotionEvent ev)和dispatchTouchEvent(MotionEvent ev) 解析

    `dispatchTouchEvent` 负责将事件传递给合适的处理者,通常是调用 `onTouchEvent(MotionEvent ev)` 方法。对于ViewGroup,它会根据 `onInterceptTouchEvent` 的结果来决定是否将事件传递给子View,或者自己处理。 ...

    浅谈Android onTouchEvent 与 onInterceptTouchEvent的区别详解

    例如,我们可以拦截触摸事件来实现滑动切换页面的效果,或者在`ViewGroup`中对特定的触摸事件进行特殊处理,而让其他事件传递给子`View`。 以文中给出的例子为例,创建了`LLayout`(继承自`FrameLayout`)和`LView`...

    android触摸消息传递

    在你的项目中,`AndroidTest_onInterceptTouchEvent`很可能是一个示例应用,用于演示如何利用`MotionEvent`和`onTouchEvent`,以及`onInterceptTouchEvent`来实现触摸事件的处理和传递。通过调试和分析这个示例,你...

    View的onInterceptTouchEvent(MotionEvent ev)和dispatchTouchEvent(MotionEvent ev)

    `onInterceptTouchEvent(MotionEvent ev)` 和 `dispatchTouchEvent(MotionEvent ev)` 是View和ViewGroup在处理触摸事件时的两个关键方法,它们共同构成了触摸事件的分发机制。了解这两个方法的工作原理对于优化用户...

    onInterceptTouchEvent

    2. **事件传递**:如果ViewGroup不拦截(即`onInterceptTouchEvent()`返回false),事件会沿着布局树向下传递到直接子视图。如果子视图消费了事件(`onTouchEvent()`返回true),事件流停止;否则,事件会回溯到父...

    Android事件处理机制ViewGroup的事件传递

    在本主题中,我们将深入探讨`ViewGroup`的事件传递,即事件分发过程。 1. **事件模型** Android事件处理基于一个简单的模型:当用户与屏幕上的UI元素交互时,系统会产生事件(如点击、滑动等)。这些事件首先被最...

    Android事件传递机制

    在Android系统中,事件传递机制是用户界面交互的核心部分,主要处理用户与屏幕的各种触摸操作。这个机制确保了用户点击屏幕时,相应的视图能够正确地接收到并响应这些事件。我们今天将深入探讨Android的触摸事件...

    Android TouchEvent事件传递

    1. 视图滑动:在实现滑动效果时,通常需要在ViewGroup的onInterceptTouchEvent()中判断滑动方向,当满足滑动条件时拦截事件,否则让事件传递给子View。 2. 多点触控:Android支持同时处理多个MotionEvent,通过...

    android Touch事件传递机制

    在Android系统中,触摸事件(Touch Events)是用户与设备交互的主要方式,它涉及到了复杂的事件传递机制。本文将深入探讨Android的触摸事件处理流程,包括事件的产生、分发以及处理过程,以实例的形式帮助开发者理解...

    事件传递机制Demo

    在Android开发中,事件传递机制是用户界面交互的核心部分,它决定了用户在屏幕上触摸或点击时,事件如何在各个View之间进行分发。本Demo,"事件传递机制Demo",着重展示了这一机制的工作原理和常见应用场景。我们...

    android事件传递机制

    在Android系统中,事件传递机制是用户界面交互的基础,它涉及到Activity、View、 ViewGroup等组件之间的协同工作。本文将深入探讨这一机制,帮助你理解如何在Android应用中处理触摸事件。 1. 触摸事件的起源 触摸...

    android 事件传递demo

    在Android开发中,事件传递是应用界面交互的关键部分,尤其是触摸事件(Touch Event)的处理。本示例“android事件传递demo”旨在演示如何在Android应用程序中管理触摸事件的分发流程,帮助开发者理解并有效地处理用户...

    Android中Touch事件的传递

    ViewGroup的onInterceptTouchEvent(MotionEvent ev)方法可以拦截事件传递,这个方法默认返回false,表示不拦截。如果重写这个方法并返回true,那么Touch事件就不会被传递给ViewGroup的子控件,而是转而由ViewGroup...

    Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解

    为了调试和优化触摸事件处理,开发者可以使用Logcat输出`MotionEvent`的信息,或者使用Android Studio的Layout Inspector查看视图树中的事件传递路径。此外,理解Android的触摸事件标志(如ACTION_DOWN、ACTION_UP、...

    android Touch触发事件的生命周期

    2. **Intercept阶段**:在事件传递过程中,ViewGroup可以通过重写`onInterceptTouchEvent()`方法来拦截事件。如果`onInterceptTouchEvent()`返回true,那么后续的事件将不再传递给子View,而是由当前ViewGroup处理。...

    android中dispatchTouchEvent和onInterceptTouchEvent研究

    但如果LinearLayout有需要响应触摸的子View,那么就需要在ScrollView的`onInterceptTouchEvent`中判断,只有当ScrollView没有滑动需求时,才允许事件传递给LinearLayout。 了解这两个方法的工作机制后,开发者可以...

Global site tag (gtag.js) - Google Analytics