android 事件处理机制之 requestDisallowInterceptTouchEvent

当手指触摸到屏幕时,系统就会调用相应 View 的 onTouchEvent,并传入一系列的 ACTION 。当有多个层级的 View 时,在父层级允许的情况下,这个 ACTION 会一直向下传递直到遇到最深层的 View 。所以 Touch 事件最先调用的是最底层 View 的 onTouchEent,如果 View 的 onTouchEvent 接收到某个 Touch ACTION 并作了相应处理,最后有两种返回方式: true 和 false。return true 会告诉系统当前的 View 需要处理这次的 Touch 事件,以后的系统发出的ACTION_MOVEACTION_UP 还是需要继续监听并接收的,而且这次的ACTION 已经被处理掉了,父层的 View 是不可能触发 onTouchEvent 了。所以每一个ACTION 最多只能有一个 onTouchEvent 接口返回true。如果 return false,便会通知系统,当前 View 不关心这一次的 Touch 事件,此时这个 ACTION 会传向父级,调用父级 View 的 onTouchEvent。但是这一次的 Touch 事件之后发出的任何 ACTION ,该 View 都不会再接受,onTouchEvent 在这一次的touch事件中再也不会触发,即一旦某个View返回 false,那么之后的ACTION_MOVEACTION_UP 等 ACTION 就不会再传入这个 View,但是下一次 Touch 事件的 ACTION 还是会传进来的。

前面说了底层的 View 能够接收到这次的事件有一个前提条件:在父层级允许的情况下。假设不改变父层级的 dispatch 方法,在系统调用底层 onTouchEvent 之前会先调用 父 View 的 onInterceptTouchEvent 方法判断,父层 View 是不是要截获本次 Touch 事件之后的 ACTION 。如果 onInterceptTouchEvent 返回true,那么本次 Touch 事件之后的所有 ACTION 都不会再向深层的 View 传递,统统都会传给父层 View 的 onTouchEvent,即父层已经截获了这次 Touch 事件,之后的ACTION 也不必询问 onInterceptTouchEvent,在这次的 Touch 事件之后发出的ACTION 时 onInterceptTouchEvent 不会再次调用,直到下一次 Touch 事件的来临。如果 onInterceptTouchEvent 返回false,那么本次 ACTION 将发送给更深层的View,并且之后的每一次 ACTION 都会询问父层的 onInterceptTouchEvent需不需要截获本次 Touch 事件。只有 ViewGroup 才有 onInterceptTouchEvent 方法,因为一个普通的View肯定是位于最深层的View,Touch 事件能够传到这里已经是最后一站了,肯定会调用View的onTouchEvent。

对于底层View来说,调用 getParent().requestDisallowInterceptTouchEvent(true); 方法,可以阻止父View 截获 Touch 事件。一旦底层 View 收到 Touch 的 ACTION 后调用这个方法那么父层 View 就不会再调用onInterceptTouchEvent 了,也无法截获以后的 ACTION 。

用例子总结一下 onInterceptTouchEvent 和 onTouchEvent 的调用顺序:
假设最顶层 View 叫 OuterLayout,中间层 View叫InnerLayout,最底层 View 叫 MyVIew 。调用顺序是这样的(假设各个函数返回的都是 false)
OuterLayout.onInterceptTouchEvent->InnerLayout.onInterceptTouchEvent -> MyView.onTouchEvent -> InnerLayout.onTouchEvent->OuterLayout.onTouchEvent。

@Override    
    public boolean dispatchTouchEvent(MotionEvent ev) {   
        getParent().requestDisallowInterceptTouchEvent(true);  
        return super.dispatchTouchEvent(ev);    
    }  

这句话的意思是告诉父view,我的事件我自己处理。

public boolean onTouch(View v, MotionEvent event) {  
     switch (event.getAction()) {  
     case MotionEvent.ACTION_MOVE:   
         pager.requestDisallowInterceptTouchEvent(true);  
         break;  
     case MotionEvent.ACTION_UP:  
     case MotionEvent.ACTION_CANCEL:  
         pager.requestDisallowInterceptTouchEvent(false);  
         break;  
     }  
}  

也可以写成类似于上面那样,当用户按下的时候,我们告诉父组件,不要拦截我的事件(这个时候子组件是可以正常响应事件的),拿起之后就会告诉父组件可以阻止。当ScrollView中嵌套ListView产生冲突时,就可以用这种方法解决。

参考:http://blog.csdn.net/chaihuasong/article/details/17499799

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值