ViewGroup继承自View,不少方法都和View中同样,不一样的是它重载了dispatchTouchEvent()
方法,而且它多了一个自身的方法onInterceptTouchEvent()
。android
dispatchTouchEvent()
中,会对子View进行递归,将dispatchTouchEvent()
传递给它的每个子View,若是某一个子View在ACTION_DOWN
的时候没有消费或者拦截事件,那么这个子View后续也将没法收到ACTIION_MOVE
和ACTION_UP
等事件。web
ViewGroup能够在onInterceptTouchEvent()
中拦截事件,onInterceptTouchEvent()
在以后执行,若是返回true
,则会执行自身的onTouchEvent()
方法,但后续onInterceptTouchEvent()
和onTouchEvent()
将不会调用。ide
ViewGroup若是onInterceptTouchEvent()
返回false
,那么ViewGroup后续是否继续调用dispatchTouchEvent()
取决于子View是否消费触摸事件。svg
ViewGroup若是返回在dispatchTouchEvent()
中返回false
,那么后续全部的触摸操做都不会再执行!spa
ViewGroup在dispatchTouchEvent()
中return true
和return super.dispatchTouchEvent(ev)
会致使触摸结果不同!code
自定义一个ViewGroup继承LinearLayout,展现ViewGroup对触摸事件的拦截。子View默认消费此事件。xml
此时:
ViewGroup:dispatchTouchEvent()
为super.dispatchTouchEvent(ev)
,onInterceptTouchEvent()
为false
,OnTouchEvent()
为false
。
子View:dispatchTouchEvent()
返回true
,OnTouchEvent()
返回true
。继承
Log打印:递归
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down View dispatchTouchEvent down View onTouchEvent down zw: LinearLayout dispatchTouchEvent move LinearLayout onInterceptTouchEvent move View dispatchTouchEvent move View onTouchEvent move zw: LinearLayout dispatchTouchEvent up LinearLayout onInterceptTouchEvent up View dispatchTouchEvent up View onTouchEvent up
能够看见,子View将事件消费掉了,所以ViewGroup没有调用OnTouchEvent()
方法。事件
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> View.dispatchTouchEvent(DOWN)
> View.OnTouchEvent(DOWN)
>
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE)
> ViewGroup.onInterceptTouchEvent(MOVE)
> View.dispatchTouchEvent(MOVE)
> View.OnTouchEvent(MOVE)
>
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP)
> ViewGroup.onInterceptTouchEvent(UP)
> View.dispatchTouchEvent(UP)
> View.OnTouchEvent(UP)
> 结束
此时:
ViewGroup:dispatchTouchEvent()
为super.dispatchTouchEvent(ev)
,onInterceptTouchEvent()
为false
,OnTouchEvent()
为false
。
子View:dispatchTouchEvent()
返回false
,OnTouchEvent()
返回false
。
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down View dispatchTouchEvent down View onTouchEvent down LinearLayout onTouchEvent down
能够看见,子View没有将事件消费掉,所以ViewGroup调用OnTouchEvent()
方法。
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> View.dispatchTouchEvent(DOWN)
> View.OnTouchEvent(DOWN)
> ViewGroup.onTouchEvent(DOWN)
> 结束
此时:
ViewGroup:dispatchTouchEvent()
为super.dispatchTouchEvent(ev)
,onInterceptTouchEvent()
为true
,OnTouchEvent()
为false
。
子View:dispatchTouchEvent()
返回true
,OnTouchEvent()
返回true
。
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down LinearLayout onTouchEvent down
能够看见,子View没有将事件消费掉,由于ViewGroup的onInterceptTouchEvent()
返回了true
,拦截了这次事件,可是它自己也没有消费,所以,ACTION_DOWN后面没有再继续执行了。
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> ViewGroup.onTouchEvent(DOWN)
> 结束
此时:
ViewGroup:dispatchTouchEvent()
为super.dispatchTouchEvent(ev)
,onInterceptTouchEvent()
为true
,OnTouchEvent()
为true
。
子View:dispatchTouchEvent()
返回true
,OnTouchEvent()
返回true
。
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down LinearLayout onTouchEvent down zw: LinearLayout dispatchTouchEvent move LinearLayout onTouchEvent move zw: LinearLayout dispatchTouchEvent up LinearLayout onTouchEvent up
能够看见,子View没有将事件消费掉,由于ViewGroup的onInterceptTouchEvent()
返回了true
,拦截了这次事件,可是它自己消费了这次事件,所以,只有ViewGroup自身在消费本次触摸事件。
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> ViewGroup.onTouchEvent(DOWN)
>
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE)
> ViewGroup.onTouchEvent(MOVE)
>
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP)
> ViewGroup.onTouchEvent(UP)
>
此时:
ViewGroup:dispatchTouchEvent()
为super.dispatchTouchEvent(ev)
,onInterceptTouchEvent()
为false
,OnTouchEvent()
为true
。
子View:dispatchTouchEvent()
返回true
,OnTouchEvent()
返回true
。
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down View dispatchTouchEvent down View onTouchEvent down zw: LinearLayout dispatchTouchEvent move LinearLayout onInterceptTouchEvent move View dispatchTouchEvent move View onTouchEvent move zw: LinearLayout dispatchTouchEvent up LinearLayout onInterceptTouchEvent up View dispatchTouchEvent up View onTouchEvent up
能够看见,若是ViewGroup的onInterceptTouchEvent()
没有返回true
而dispatchTouchEvent()
返回true
,那么即便OnTouchEvent()
返回的是true
,也不会调用OnTouchEvent()
方法,须要根据子View的消费状况来判断!
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> View.dispatchTouchEvent(DOWN)
> View.onTouchEvent(DOWN)
>
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE)
> ViewGroup.onInterceptTouchEvent(MOVE)
> View.dispatchTouchEvent(MOVE)
> View.onTouchEvent(MOVE)
>
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP)
>ViewGroup.onInterceptTouchEvent(UP)
> View.dispatchTouchEvent(UP)
> View.onTouchEvent(UP)
>
当ViewGroup在onInterceptTouchEvent()
返回true
消费事件后,子View则没法消费此触摸事件,此时,子View若是必定要消费此触摸事件的话,可使用getParent().requestDisallowInterceptTouchEvent(true)
来让ViewGroup不拦截本次事件。
可是此方法须要知足一个条件,就是ViewGroup在onInterceptTouchEvent()
的ACTION_DOWN时不要拦截,若是拦截了,那么此方法失效。
此时:
ViewGroup:dispatchTouchEvent()
为true
,onInterceptTouchEvent()
在ACITON_DOWN时为false
,其他返回true
,OnTouchEvent()
为true
。
子View:dispatchTouchEvent()
返回true
,OnTouchEvent()
返回true
。
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down View dispatchTouchEvent down View onTouchEvent down zw: LinearLayout dispatchTouchEvent move LinearLayout onInterceptTouchEvent move LinearLayout dispatchTouchEvent move LinearLayout onTouchEvent move zw: LinearLayout dispatchTouchEvent up LinearLayout onTouchEvent up
能够看见,子View只有dispatchTouchEvent(DOWN)
和onTouchEvent(DOWN)
被调用了,其他的都被拦截了。(这就是ViewGroup的onInterceptTouchEvent()
必须在ACTION_DOWN时返回false
的缘由,否则子View根本没有调用的机会)
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> View.dispatchTouchEvent(DOWN)
> View.onTouchEvent(DOWN)
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE)
> ViewGroup.onInterceptTouchEvent(MOVE)
> ViewGroup.dispatchTouchEvent(MOVE)
> ViewGroup.onTouchEvent(MOVE)
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP)
> ViewGroup.onTouchEvent(UP)
> 结束
基本和上面同样,只是子View在onTouchEvent()
的ACTION_DOWN中调用代码:
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: getParent().requestDisallowInterceptTouchEvent(true); Log.e("zw","onTouchEvent down"); break; case MotionEvent.ACTION_MOVE: Log.e("zw","onTouchEvent move"); break; case MotionEvent.ACTION_UP: Log.e("zw","onTouchEvent up"); break; } return true; }
Log打印:
zw: LinearLayout dispatchTouchEvent down LinearLayout onInterceptTouchEvent down View dispatchTouchEvent down View onTouchEvent down zw: LinearLayout dispatchTouchEvent move View dispatchTouchEvent move View onTouchEvent move zw: LinearLayout dispatchTouchEvent up View dispatchTouchEvent up View onTouchEvent up
能够看见,本次触摸事件被子View强制消费掉了。
调用顺序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN)
> ViewGroup.onInterceptTouchEvent(DOWN)
> View.dispatchTouchEvent(DOWN)
> View.onTouchEvent(DOWN)
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE)
> View.dispatchTouchEvent(MOVE)
> View.onTouchEvent(MOVE)
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP)
> View.dispatchTouchEvent(UP)
>View.onTouchEvent(UP)
> 结束
一、若是ViewGroup要消费触摸事件的话,必定要在onInterceptTouchEvent()
返回true
,不然它是否调用onTouchEvent()
方法取决于子View是否消费此事件!
二、ViewGroup的dispatchTouchEvent()
中尽可能不要直接返回true
或false
,由于这样致使ViewGroup不会再去分发任何事件!最好返回super.dispatchTouchEvent(ev)
!
三、子View能够经过调用getParent().requestDisallowInterceptTouchEvent(true)
方法来强制消费事件(有限制条件)。