onInterceptTouchEvent() 和 onTouchEvent()

onInterceptTouchEvent()  事件拦截,默认返回false。
onTouchEvent()                 事件处理,默认返回false。

onInterceptTouchEvent():该方法是从父控件子控件传递,直到有子ViewGroup拦截或者所有子ViewGroup都没有拦截,然后再通过子ViewGroup中onTouchEvent()的返回值,依次从子控件传递给父控件
(先不要纠结down,move,up事件是怎么传递的,这里可能执行父控件的onInterceptTouchEvent()中的move事件,有可能执行父控件的onTouchEvent()中的move事件)
onTouchEvent():该方法依次从子控件传递给父控件

备注:众所周知这两个方法的返回值要么是true要么是false。

onInterceptTouchEvent(): 返回true,表示该层的ViewGroup拦截了事件。 返回false,表示该层ViewGroup不拦截事件。

onTouchEvent():返回true,表示该层ViewGroup自己处理(消费)触摸事件。返回false表示该层ViewGroup不处理触摸事件。

先来看下布局结构:
这里写图片描述

xml布局代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.project.architecture.views.ontouch.MyScrollView
        android:id="@+id/sv_my"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dip"
        android:background="#ff00ff" >

        <com.project.architecture.views.ontouch.LinearLayout1
            android:id="@+id/ll_1"
            android:layout_width="match_parent"
            android:layout_height="700dip"
            android:layout_margin="50dip"
            android:background="#00ffff"
            android:orientation="vertical" >

            <com.project.architecture.views.ontouch.LinearLayout2
                android:id="@+id/ll_2"
                android:layout_width="match_parent"
                android:layout_height="600dip"
                android:layout_margin="60dip"
                android:background="#0000ff"
                android:orientation="vertical" >

                <com.project.architecture.views.ontouch.ButtonTest
                    android:id="@+id/btn_test"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="adfsd"
                    android:visibility="gone" />
            </com.project.architecture.views.ontouch.LinearLayout2>
        </com.project.architecture.views.ontouch.LinearLayout1>
    </com.project.architecture.views.ontouch.MyScrollView>

</RelativeLayout>

该结构就是: ScrollView+LinearLayout1+LinearLayout2+ButtonTest

OK,接下来看几种情况的分析:

例1:当父类既不拦截也不处理,子类也不拦截也不处理,这就是系统默认的事件处理。也就是onInterceptTouchEvent() 和 onTouchEvent()都返回false。

结果:onInterceptTouchEvent()中的down事件,依次从父控件向下传递给子控件,然后再根据子控件onTouchEvent()方法中down事件的返回值将down事件依次从子控件向上传递给父控件,最后执行父控件的move和up事件。

E/scrollview(27795): sv intercept action:ACTION_DOWN dx = 586.0 dy = 1170.0
E/ll-1 ==(27795): ll-1 intercept action:ACTION_DOWNdx = 586.0 dy = 1170.0
E/ll-2 ==(27795): ll-2 intercept action:ACTION_DOWN
W/ll-2 ==(27795): ll-2 onTouchEvent action:ACTION_DOWN
W/ll-1 ==(27795): ll-1 onTouchEvent action:ACTION_DOWN586.0 dy = 1170.0
W/scrollview(27795): sv onTouchEvent action:ACTION_DOWN
I/scrollview(27795): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(27795): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(27795): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(27795): sv onTouchEvent  action:ACTION_UP

onInterceptTouchEvent()事件从ScrollView–>LinearLayout1–>LinearLayout2
onTouchEvent()事件从LinearLayout2–>LinearLayout1–>ScrollView

例2:父类onInterceptTouchEvent()down事件返回true。拦截事件,自己处理,执行自己的onTouchEvent()方法。不再传递给子ViewGroup。

E/scrollview(29009): sv intercept action:ACTION_DOWN dx = 627.0 dy = 1242.0
W/scrollview(29009): sv onTouchEvent action:ACTION_DOWN
I/scrollview(29009): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(29009): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(29009): sv onTouchEvent  action:ACTION_MOVE

例3:父类onInterceptTouchEvent()down事件返回false。代表不拦截事件,则down事件传递给子ViewGroup的onInterceptTouchEvent()方法。

 3-1:子ViewGroup的onInterceptTouchEvent()返回false。 onTouchEvent()返回true(代表自己处理)。
 后续的move和up事件执行顺序:子ViewGroup和父类的move事件交互执行,先执行子ViewGrouponTouchEvent中的move事件,在执行父类onInterceptTouchEvent中的move事件。

(子类没有拦截,但是处理(消费)了自己的onTouchEvent事件,那么父类就告诉子类,你每处理一次就向我反馈一次,不合理就不让你处理了。父类具有监管的权利

E/scrollview(9480): sv intercept action:ACTION_DOWN dx = 797.0 dy = 1186.0
E/ll-1 ==(9480): ll-1 intercept action:ACTION_DOWNdx = 797.0 dy = 1186.0
W/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_DOWN797.0 dy = 1186.0
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(9480): sv intercept action:ACTION_MOVE
I/ll-1 ==(9480): ll-1 onTouchEvent action:ACTION_CANCEL
I/scrollview(9480): sv onTouchEvent action:ACTION_MOVE
I/scrollview(9480): sv onTouchEvent action:ACTION_MOVE

3-2:子ViewGroup的onInterceptTouchEvent()返回false。onTouchEvent()返回false。
后续的move事件传递给父类的onTouchEvent。
(子类没有拦截,也没有处理,那就将事件回传给父类处理)

E/scrollview(11009): sv intercept action:ACTION_DOWN dx = 789.0 dy = 1084.0
E/ll-1 ==(11009): ll-1 intercept action:ACTION_DOWNdx = 789.0 dy = 1084.0
W/ll-1 ==(11009): ll-1 onTouchEvent action:ACTION_DOWN789.0 dy = 1084.0
W/scrollview(11009): sv onTouchEvent action:ACTION_DOWN
 I/scrollview(11009): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(11009): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(11009): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(11009): sv onTouchEvent  action:ACTION_MOVE
3-3:子ViewGroup的onInterceptTouchEvent()返回true。 onTouchEvent()返回false。 
后续的move事件传递给父类的onTouchEvent。(子类拦截了(该层以后的子view不再接收事件),但是没有处理,那就回传给父类处理)
E/scrollview(11705): sv intercept action:ACTION_DOWN dx = 818.0 dy = 1075.0
E/ll-1 ==(11705): ll-1 intercept action:ACTION_DOWNdx = 818.0 dy = 1075.0
W/ll-1 ==(11705): ll-1 onTouchEvent action:ACTION_DOWN818.0 dy = 1075.0
W/scrollview(11705): sv onTouchEvent action:ACTION_DOWN
I/scrollview(11705): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(11705): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(11705): sv onTouchEvent  action:ACTION_MOVE
3-4:子ViewGroup的onInterceptTouchEvent()返回true。 onTouchEvent()返回true。
down事件传递给子ViewGroup的onInterceptTouchEvent和onTouchEvent方法中。后续的move和up事件交互执行,先执行父类中onInterceptTouchEvent的move事件在执行子ViewGroup中onTouchEvent的move事件。(子类拦截处理或者不处理,父类具有监管的权利)
E/scrollview(12676): sv intercept action:ACTION_DOWN dx = 814.0 dy = 1029.0
E/ll-1 ==(12676): ll-1 intercept action:ACTION_DOWNdx = 814.0 dy = 1029.0
W/ll-1 ==(12676): ll-1 onTouchEvent action:ACTION_DOWN814.0 dy = 1029.0
E/scrollview(12676): sv intercept  action:ACTION_MOVE
I/ll-1 ==(12676): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(12676): sv intercept  action:ACTION_MOVE
I/ll-1 ==(12676): ll-1 onTouchEvent action:ACTION_MOVE
E/scrollview(12676): sv intercept  action:ACTION_MOVE
I/ll-1 ==(12676): ll-1 onTouchEvent **action:ACTION_CANCEL**
I/scrollview(12676): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(12676): sv onTouchEvent  action:ACTION_MOVE
I/scrollview(12676): sv onTouchEvent  action:ACTION_MOVE

如果仔细看你会发现,3-2和3-4中当子类的onTouchEvent返回true,但是经过几次事件传递之后(或者某些条件下),父类发现子类并没有处理,那就会触发子类的ACTION_CANCEL事件,不再让子类处理,事件回传给父类处理。


再反复的测试中会发现2个问题:
1,触发ACTION_CANCEL事件
2,Invalid pointerId=-1 in onTouchEvent

action_cancel 触发条件:
1,子类onTouchEvent返回true,但是没有做任何处理操作。
2,父类down事件不拦截,在move事件滑动时,父类在某一条件满足时进行拦截,就会导致子类不再接受事件传递。
这个时候只能在父类move事件中去调用 子ViewGroup的onTouchEvent()方法。

case MotionEvent.ACTION_MOVE:
    sy = getScrollY();
    mx = ev.getRawX();
    my = ev.getRawY();
    float delatY = dy-my; // 大于0 向上   小于0 向下。
    if(delatY>0){

    }else if(delatY<0 && getScrollY()==0){
      lv_movies.onTouchEvent(ev);// 直接调用子类的onTouchEvent方法
      return false;
    }
    break;

Invalid pointerId=-1 in onTouchEvent:

Android 4.4 Invalid pointerId=-1 in onTouchEvent
而Android 4.4以下,会输出:pointerIndex out of range

这个是因为父类down事件没有拦截(直接返回false,并且没有调用super方法),在move事件滑动中,父类在某一条件满足时进行拦截,就会导致子类不再接受事件传递,而触发子ViewGroup的action_cancel,然后在父类的onTouchEvent中就会出现Invalid pointerId=-1 in onTouchEvent的错误。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值