android中 当我们的手指触摸屏幕将产生一个事件,
(假设 这个过程中如果没有显示的去拦截该事件的话)
这个事件会逐级传递到视图的最底层,即使在中间某些视图会响应这个事件( 这个视图也不会去消费这个事件), 仍然是会传递到底层(底层不响应该事件),然后再由底层回传到顶层,在传回顶层的过程中 , 原先会响应该事件的视图才会去消费这个事件例如在左图中 A
B(会响应该事件) C D(假设在这整个过程中 没有做任何特殊的处理)
事件从A开始向D传递,这个时候B不会消费这个事件
只有当事件从D回传到A的过程中 B才回去消费这个事件。 但是,假设D也会响应这个事件 ,那么该事件将会被D所消费 这个时候事件停止传递 那么B也就没有机会再去消费该事件了。也就是说这个时候的B就相当于无视了这个触摸(点击)事件。
那为什么传到底层D时事件就会被消费呢? (假设底层D会响应该事件) 因为,VIewGroup才有 onInterceptTouchEvent()方法 ,而view中是没有的 ,也就是说 当view响应事件时 就一定会去消费该事件,因为它别无选择 只能消费掉该事件。 而ViewGroup则默认是不拦截事件 而是分发给子View的.下面是关于拦截与分发的三个方法:
dispatchTouchEvent()方法用于事件的分发,Android中所有的事件都必须经过这个方法的 分发,
然后决定是自身消费当前事件还是继续往下分发给子控件处理。返回true表示不继续分发, 事件没有被消费。返回false则继续往下分发, 如果是 ViewGroup则分发给onInterceptTouchEvent进行判断是否拦截该事件。onInterceptTouchEvent()是ViewGroup中才有的方法,View中没有, ( 即ViewGroup中的拦截的方法)
它的作用是 负责事件的拦截,返回true的时候表示拦截当前事件, 不继续往下分发,交给自身的onTouchEvent进行处理(即会触发onTouchEvent()方法)。返回false则不拦截, 继续往下传。这是ViewGroup特有的方法,因为ViewGroup中可能还有子View,而在Android中View中是不能再包含子View的。 onTouchEvent()方法用于事件的处理,返回true表示消费处理当前事件, 返回false则不处理,交给子控件进行继续分发。
补充与总结: 一个事件的传递包含正向传递(父view传给子view的过程)和回传传递(子view传给父view的过程)
在正向传递中 父view可以拦截事件,使该事件不传递给子view ;相同的,在回传传递中,子view也可以反拦截事件,使之不再回传给父view//在X轴和Y轴滑动的距离
float DX = Math.abs(endX-downX); float DY = Math.abs(endY-downY); if(DX > DY&&DX>8){ //水平方向滑动 //响应侧滑 //反拦截-事件给SlideLayout getParent().requestDisallowInterceptTouchEvent(true); (实际上是父view调用了反拦截的方法) }
对于各种事件的传递和分发的冲突的问题 重点是要分析好各个视图之间的从属关系
然后1.判断(反)拦截与否,2.判断水平滑动是否大于竖直滑动核心思想是 : 让不同的操作做好自己的事件 不要干扰到其他人的事情
例如侧滑菜单中 视图的关系假设是这样的
activity ——》relatilayout--》listview——》slidelayout(自定义viewGroup)——》1.content(textview) ——》 2.menu(textview)侧滑菜单 (1.处理侧滑时与listView下滑的冲突 解决:反拦截事件 (实际上是slidelayout与slidelayout之间的冲突
也就是下滑的这个事件slidelayout不响应而listview响应) 2.处理listView条目点击事件与侧滑时的冲突(通过分析从属关系得知,实际上是content与slidelayout之间的冲突 也就是content把事件消费了,slidelayout得不到事件从而无法滑动了) 解决:拦截事件)