现在的位置: 首页 > 综合 > 正文

onInterceptTouchEvent 和 onTouchEvent 调用时序

2013年02月16日 ⁄ 综合 ⁄ 共 7908字 ⁄ 字号 评论关闭


public

boolean

onInterceptTouchEvent
(MotionEvent
ev)

Since: API
Level 1

Implement this method to
intercept all touch screen motion events. This
allows you to watch events as they are dispatched to your children, and
take ownership of the current gesture at any point.

Using this function takes some care, as it has a fairly
complicated
interaction with View.onTouchEvent(MotionEvent)

,
and using it requires implementing
that method as well as this one in the correct way. Events will be
received in the following order:

  1. You will receive the down event here.
  2. 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.
  3. 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().
  4. 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.
Parameters
ev The motion event being dispatched down the hierarchy.
Returns
  • Return true to steal motion events from the
    children and have
    them dispatched to this ViewGroup through onTouchEvent().
    The current target will receive an ACTION_CANCEL event, and no further
    messages will be delivered here.
  •  

  •  

  •  

  •  

  • 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




抱歉!评论已关闭.