onInterceptTouchEvent dispatchTouchEvent requestDisallowInterceptTouchEvent

1. dispatchTouchEvent :负责事件分发,由外层向里层传递。

2. onInterceptTouchEvent  :只有ViewGroup有,可以拦截向下传递的事件。

3. requestDisallowInterceptTouchEvent:由孩子调用,可以阻止父Viewgroup拦截事件。

如上所述:第2和第3个函数是矛盾的,要是同时使用,哪个为准呢?我一直有这个疑问。

我个人的理解:当Viewgroup收到down事件,会先调用onInterceptTouchEvent,如果onInterceptTouchEvent返回true,孩子view不会有任何事件传入;但如果Viewgroup没有拦截down事件,让子View获得down事件,这样子view就有禁止父Viewgroup拦截的机会。还有重要的一点:只有子View对事件有响应(return true),父Viewgroup的onInterceptTouchEvent中才会出现 up和move等事件;否则Viewgroup的onInterceptTouchEvent中只有down事件。是否disallowIntercept是在onInterceptTouchEvent调用前判断的,因此可以在子View中控制父Viewgroup的对其他action是否拦截(通过requestDisallowInterceptTouchEvent)。有什么不对请告知!



自定义一个Viewgroup、ViewA和ViewB,重写dispatchTouchEvent ,onInterceptTouchEvent

onTouchEvent。

界面和默认的点击处理事件如下:


由日志可以看出:

1. dispatchTouchEvent 是由外往里传递,当然不是说Viewgroup包含多少子View就传递多少,在传递过程会做坐标判断。(只是传递给包含点击坐标的子view)。

这如下段代码摘抄至android2.2的Viewgroup dispatchTouchEvent 源码中。

 if (frame.contains(scrolledXInt, scrolledYInt)) {
                            // offset the event to the view's coordinate system
                            final float xc = scrolledXFloat - child.mLeft;
                            final float yc = scrolledYFloat - child.mTop;
                            ev.setLocation(xc, yc);
                            child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
                            if (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
                            // The event didn't get handled, try the next view.
                            // Don't reset the event's location, it's not
                            // necessary here.
                        }
                    }

2. onTouchEvent是由里向外传递,若没有任何view响应,就交给activity处理。若其中有一个响应down事件,

该次触摸事件都会交予它处理(这是在没有拦截的基础上)。

3. onInterceptTouchEvent 是在dispatchTouchEvent 后调用的,默认返回值是false。


onTouchEvent、onInterceptTouchEvent 和dispatchTouchEvent 返回值网上有很多资料,

onInterceptTouchEvent 返回true,Viewgroup就会调用自己的onTouchEvent。()

http://download.csdn.net/detail/fengyun703/9318719,这有实例代码,可以自己做实验。


推荐一篇很牛的文章,对事件传递讲解十分清楚。

xiaanming的博客http://blog.csdn.net/xiaanming/article/details/21696315#comments


在stackoverflow上找到这句话:

onInterceptTouchEvent only get called if the parent has a child view which returns "true" 

from onTouchEvent. Once the child returns true, the parent now has a chance to

intercept that event.

自己做了实验:

如下图:

onInterceptTouchEvent 只在down事件处理中运行,只有Viewgroup的孩子响应该事件(

即return true),Viewgroup才有机会去拦截后续事件(即onInterceptTouchEvent 中才有move和up等事件)。

否则onInterceptTouchEvent中只有down事件。这也是正常思路:孩子有响应才去拦截。(最好能看源码,但看懂源码还有很困难,只能先从实验开始)




onInterceptTouchEvent  和requestDisallowInterceptTouchEvent到底哪个说了算。

onInterceptTouchEvent  在Viewgroup接到dwon事件后调用,若返回true,根本不会传递到子view。

但如果onInterceptTouchEvent  在down事件返回false,子view就有机会requestDisallowInterceptTouchEvent。


实验1:子View可以禁止父Viewgroup拦截事件。

我让Viewgroup在down事件时没有拦截,其他事件拦截。view的dispatchTouchEvent中调用requestDisallowInterceptTouchEvent,且view的ontouchEvent返回true。这样能实现子view禁止父viewgroup拦截触摸事件。

代码如下:

Viewgroup中:

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("test","MyViewGroup  onInterceptTouchEvent  "+ EventUtils.getMotion(ev));
        //return super.onInterceptTouchEvent(ev);
        int action = ev.getAction();
        boolean result;
        switch (action) {
case MotionEvent.ACTION_DOWN:
result = false;
break;
default:
result = true;
break;
}
       return result;
    }


ViewA中:

@Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("test", "MyViewA  dispatchTouchEvent  "+EventUtils.getMotion(event));
        getParent().requestDisallowInterceptTouchEvent(true);
        return super.dispatchTouchEvent(event);
    }

结果如下:



实验2:子View可以在不同action(更细微地)要求父Viewgroup是否拦截事件。

我让Viewgroup在down事件时没有拦截,其他事件拦截,而且onTouchEvent返回true。view的dispatchTouchEvent中调用requestDisallowInterceptTouchEvent,且view的ontouchEvent返回true。

Viewgroup代码如下:

  @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //return super.onInterceptTouchEvent(ev);
        int action = ev.getAction();
        boolean result;
        switch (action) {
case MotionEvent.ACTION_DOWN:
result = false;
break;
default:
result = true;
break;
}
        Log.i("test","MyViewGroup  onInterceptTouchEvent  "+ EventUtils.getMotion(ev) +",  Intercept  =  "+ result);
       return result;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("test","MyViewGroup  onTouchEvent  "+ EventUtils.getMotion(event));
       //return super.onTouchEvent(event);
       return true;
    }


ViewA代码:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
boolean disallow = false;
switch (action) {
case MotionEvent.ACTION_DOWN:
disallow = true;
break;
case MotionEvent.ACTION_MOVE:
disallow = false;
break;
case MotionEvent.ACTION_UP:
disallow = false;
break;
default:
break;
}
getParent().requestDisallowInterceptTouchEvent(disallow);
Log.i("test",
"MyViewA  dispatchTouchEvent  " + EventUtils.getMotion(event)
+ ",  disallow =   " + disallow);
return super.dispatchTouchEvent(event);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i("test", "MyViewA  onTouchEvent   " + EventUtils.getMotion(event));
// return super.onTouchEvent(event);
return true;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值