Android拦截的一点其他理解

    相信大家看过很多事件分发拦截的机制了,很多原理就不再多说了,说点不同的吧,那就是拦截的重点只是拦截下来不再给子View了,但是这里与父View的交互还需要再处理的。

    来写个Demo试试吧,比较简单,就是父ViewGroup包了一个子View。

@Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("父","父拦截down");
        }
        if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
            Log.e("父","父拦截move");
            return true;
        }
        if (arg0.getAction() == MotionEvent.ACTION_UP) {
            Log.e("父","父拦截up");
        }
        return super.onInterceptTouchEvent(arg0);
    }

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("父","父处理down");
            return true;
        }
        if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
            Log.e("父","父处理move");
            return true;
        }
        if (arg0.getAction() == MotionEvent.ACTION_UP) {
            Log.e("父","父处理up");
            return true;
        }

        return super.onTouchEvent(arg0);
    }

 

子View的关键代码

@Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("子","子拦截down");
        }
        if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
            Log.e("子","子拦截move");
        }
        if (arg0.getAction() == MotionEvent.ACTION_UP) {
            Log.e("子","子拦截up");
        }
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
            Log.e("子","子处理down");
            return true;
        }
        if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
            Log.e("子","子处理move");
            return true;
        }
        if (arg0.getAction() == MotionEvent.ACTION_UP) {
            Log.e("子","子处理up");
            return true;
        }

        return super.onTouchEvent(arg0);
    }

    这里子View是完全想得到事件的整个控制的,可以看到两个方法返回都是true,以前的理解是子View获得一个事件的处理权后并返回true那么后续的事件都可以由自己处理。现在我们试下子View已经处理完Down的事件后,对Move事件,父布局此时想拦截并处理,会发生什么效果。

 

05-02 11:47:12.552 21913-21913/com.demo.zhang E/父: 父拦截down
05-02 11:47:12.552 21913-21913/com.demo.zhang E/子: 子拦截down
    子处理down
05-02 11:47:12.592 21913-21913/com.demo.zhang E/父: 父拦截move
05-02 11:47:12.608 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.625 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.644 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.658 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.675 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.694 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.713 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.725 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.742 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.757 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.774 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.791 21913-21913/com.demo.zhang E/父: 父处理move
05-02 11:47:12.880 21913-21913/com.demo.zhang I/IgnoreTouchEvent: ignore up event : x = 269.5, ignore = false, ignoreUp = false, pkg = com.demo.zhang
05-02 11:47:12.880 21913-21913/com.demo.zhang E/父: 父处理up

    看到了么,从第四行开始父ViewGroup已经拦截下来Move事件,并交给自己处理了(前提父ViewGroup是想处理的,在TouchEvent返回了true)   如果父布局不处理还会往上传递这个事件,这和普通的情况并没什么不一样。所以拦截主要是针对子布局的,而不是父布局的。

 

 

    那么如果子View需要自己做不再给父布局管理,那么怎么办呢,有一个方法是

getParent().requestDisallowInterceptTouchEvent(true);

这样子View就可以处理剩余的Down Move Up事件了。

 

    然后再说分发和拦截的区别

    分发dispatchTouchEvent
    Android中所有的事件都必须经过这个方法的分发,然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发,事件被消费。返回false则继续往下分发,如果是ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件,而且在ViewGroup中会调用interceptTouchEvent()方法来判断是否继续向下分发。在View中是根据View的OnTouchEvent来决定返回值,当onTouch消费事件的时候,View的dispatchTouchEvent会返回true告诉父ViewGroup自己已经消耗掉这个事件。

不要太过在意它的返回值,看源码关注它的过程,它的过程是会调用自身的拦截以及子View的消费事件来派发的,也就是在这个过程中可能子View已经正在消费事件了(派发的过程中有调用子View的dispatchTouchEvent,而在那里又调用子View自身的onTouchEvent)。

所以这个对于一个ViewGroup来说这个返回值重点是告诉它上层的父ViewGroup,这个事件我已经消费掉了(包含子View,也可能是子View消费了)

所以也可以说当返回false的时候,是回传给父的dispatchTouchEvent,告诉它我不需要消费这个事件,让父自己处理。在源码中就可以看到父的dispatchTouchEvent在判断子的dispatchTouchEvent是false的时候就去调用自身的onTouchEvent,如果自己也不消费,继续回传它的父ViewGroup的dispatchTouchEvent。

所以总结就是父ViewGroup的dispatchTouchEvent关注的是事件在它以及它包含的子View里有没有被消费掉。
   如果interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理。此时已经完全进入interceptTouchEvent。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值