Android-onInterceptTouchEvent()和onTouchEvent()总结

老实说,这两个小东东实在是太麻烦了,很很差懂,我本身那api文档都头晕,在网上找到不少资料,才知道是怎么回事,这里总结一下,记住这个原则就会很清楚了:android

一、onInterceptTouchEvent()是用于处理事件(相似于预处理,固然也能够不处理)并改变事件的传递方向,也就是决定是否容许Touch事件继续向下(子控件)传递,一但返回True(表明事件在当前的viewGroup中会被处理),则向下传递之路被截断(全部子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()后端


二、onTouchEvent()用于处理事件,返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还容许Touch事件继续向上(父控件)传递,一但返回True,则父控件不用操心本身来处理Touch事件。返回true,则向上传递给父控件(注:可能你会以为是否消费了有关系吗,反正我已经针对事件编写了处理代码?答案是有区别!好比ACTION_MOVE或者ACTION_UP发生的前提是必定曾经发生了ACTION_DOWN,若是你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,因此ACTION_MOVE或者ACTION_UP就不能被捕获。)api



概念介绍

一、onInterceptTouchEvent()是用于处理事件(重点onInterceptTouchEvent这个事件是从父控件开始往子控件传的,直到有拦截或者到没有这个事件的view,而后就往回从子到父控件,此次是onTouch的)(相似于预处理,固然也能够不处理)并改变事件的传递方向,也就是决定是否容许Touch事件继续向下(子控件)传递,一但返回True(表明事件在当前的viewGroup中会被处理),则向下传递之路被截断(全部子控件将没有机会参与Touch事件),同时把事件传递给当前的控件的onTouchEvent()处理;返回false,则把事件交给子控件的onInterceptTouchEvent()函数

 

二、onTouchEvent()用于处理事件(重点onTouch这个事件是从子控件回传到父控件的,一层层向下传),返回值决定当前控件是否消费(consume)了这个事件,也就是说在当前控件在处理完Touch事件后,是否还容许Touch事件继续向上(父控件)传递。返回false,则向上传递给父控件,详细一点就是这个touch事件就给了父控件,那么后面的up事件就是到这里touch触发,不会在传给它的子控件。若是父控件依然是false,那touch的处理就给到父控件的父控件,那么up的事件处理都在父控件的父控件,不会触发下面的。布局

返回true,若是是子控件返回true,那么它的touch事件都在这里处理,父控件是处理不了,由于它收不到子控件传给他的touch,被子控件给拦截了。(这里啰嗦了这么多就是为了加深记忆,这个两个事件理解起来都这么麻烦了,更况且去记,记我确定是一会儿就忘的了^0^)spa

(注:可能你会以为是否消费了有关系吗,反正我已经针对事件编写了处理代码?答案是有区别!好比ACTION_MOVE或者ACTION_UP发生的前提是必定曾经发生了ACTION_DOWN,若是你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,因此ACTION_MOVE或者ACTION_UP就不能被捕获。)设计

详细介绍

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

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

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


onInterceptTouchEvent()是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()以前对相关事件进行一次拦截.

  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()处理。


    仅仅看这个官方文档解释,就能理解清楚这两个函数关系以及用途的绝对是富有经验的framework高手。
    不然,必定须要一个案例来阐释。假设咱们有这样一个layout,很是典型的

    <com.test.LayoutView1 xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="vertical" android:layout_width="fill_parent"  
        android:layout_height="fill_parent">  
        <com.test.LayoutView2  
            android:orientation="vertical" android:layout_width="fill_parent"  
            android:layout_height="fill_parent" android:gravity="center">  
            <com.test.MyTextView  
                android:layout_width="wrap_content"   android:layout_height="wrap_content"  
          />  
        </com.test.LayoutView2>  
    </com.test.LayoutView1>

    用一个示例图来解释这个layout:


    一般外围的layoutview1,layoutview2,只是布局的容器不须要响应触屏的点击事件,仅仅Mytextview须要相应点击。但这只是通常状况,一些特殊的布局可能外围容器也要响应,甚至不让里面的mytextview去响应。更有特殊的状况是,动态更换响应对象。
    那么首先看一下默认的触屏事件的在两个函数之间的传递流程。以下图:


    若是仅仅想让MyTextView来响应触屏事件,让MyTextView的OnTouchEvent返回true,那么事件流就变成以下图,能够看到layoutview1,layoutview2已经不能进入OnTouchEvent:


    另一种状况,就是外围容器想独自处理触屏事件,那么就应该在相应的onInterceptTouchEvent函数中返回true,表示要截获触屏事件,好比layoutview1做截获处理,处理流变成以下图:


    以此类推,咱们能够获得各类具体的状况,整个layout的view类层次中都有机会截获,并且能看出来外围的容器view具备优先截获权。

    当咱们去作一些相对来说具备更复杂的触屏交互效果的应用时候,常常须要动态变动touch event的处理对象,好比launcher待机桌面和主菜单(见下图),从滑动屏幕开始到中止滑动过程中,只有外围的容器view才能够处理touch event,不然就会误点击上面的应用图标或者widget.反之在静止不动的状态下则须要可以响应图标(子view)的touch事件。摘取framework中abslistview代码以下




    总结:

    仅仅经过概览性的官方文档是很难理解onInterceptTouchEvent函数的用途的,只有经过演绎这个抽象的规则,配以图文才能获取这个重要的知识。很显然,默认是返回false,不作截获。返回true以后,事件流的后端控件就没有机会处理touch事件了,把默认的事件流中每一个处理函数看做一个节点,这个节点只要返回true, 后续的事件就被截止了,这样想就很好理解。




    onInterceptTouchEvent是在ViewGroup里面定义的。Android中的layout布局类通常都是继承此类的。onInterceptTouchEvent是用于拦截手势事件的,每一个手势事件都会先调用onInterceptTouchEvent。 
    onInterceptTouchEvent()用于处理事件并改变事件的传递方向。返回值为false时事件会传递给子控件的onInterceptTouchEvent();返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件,这就是所谓的Intercept(截断)。
    onTouchEvent() 用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码?答案是有区别!好比ACTION_MOVE或者ACTION_UP发生的前提是必定曾经发生了ACTION_DOWN,若是你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,因此ACTION_MOVE或者ACTION_UP就不能被捕获。

    1. public boolean onInterceptTouchEvent(MotionEvent ev) {

    2.         int action = ev.getAction();


    3.         switch (action & MotionEvent.ACTION_MASK) {

    4.         case MotionEvent.ACTION_DOWN: {

    5.  

    6.             if (touchMode == TOUCH_MODE_FLING) {

    7.                 return true;  //fling状态,截获touch,由于在滑动状态,不让子view处理

    8.             }

    9.             break;

    10.         }


    11.         case MotionEvent.ACTION_MOVE: {

    12.             switch (mTouchMode) {

    13.             case TOUCH_MODE_DOWN:

    14.                 final int pointerIndex = ev.findPointerIndex(mActivePointerId);

    15.                 final int y = (int) ev.getY(pointerIndex);

    16.                 if (startScrollIfNeeded(y - mMotionY)) {

    17.                     return true;//开始滑动状态,截获touch事件,不让子view处理

    18.                 }

    19.                 break;

    20.             }

    21.             break;

    22.         }

    23. }

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

    25.     android:orientation="vertical" android:layout_width="fill_parent"  

    26.     android:layout_height="fill_parent">  

    27.     <com.test.LayoutView2  

    28.         android:orientation="vertical" android:layout_width="fill_parent"  

    29.         android:layout_height="fill_parent" android:gravity="center">  

    30.         <com.test.MyTextView  

    31.             android:layout_width="wrap_content"   android:layout_height="wrap_content"  

    32.       />  

    33.     </com.test.LayoutView2>  

    34. </com.test.LayoutView1>



ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.

ViewGroup里的onTouchEvent默认值是false。

View里的onTouchEvent返回默认值是true.这样才能执行屡次touch事件。

相关文章
相关标签/搜索