Android事件传递在应用内容主要方法有:
ViewGroup中有以下三种方法,View没有onInterceptTouchEvent
-
dispatchTouchEvent
- 返回true, 自己直接消耗,子节点不会继续传递事件,连自己的onInterceptTouchEvent和onTouch都不走。
- 返回false,若非根节点,则进入其父节点的Touch事件,否则只会执行根节点的dispatchTouchEvent。
- 返回super.dispatchTouchEvent(ev), 对于ViewGroup来说才能进入onInterceptTouchEvent来选择是否拦截对于子节点事件的传递。
-
onInterceptTouchEvent
- 返回true : 拦截, 子View接收不到任何事件。
- 返回false: 不拦截
-
onTouchEvent
- 返回true : 消耗此事件,onTouch在由下向上的传递过程也就因此阻断,事件结束了。
- 返回false: 不消耗此事件,事件未结束,还需要调用ViewGroup或者Activity的onTouchEvent
注意:
- 在ViewGroup中onInterceptTouchEvent返回false,那么事件继续向下传递,如果没有子view处理这个时间,即子view的onTouchEvent返回false,则最后还是由ViewGroup去处理这个事件,也就是执行自己的onTouchEvent事件
- onTouch调用前会自动调用onInterceptTouchEvent,如果onInterceptTouchEvent返回false,则不会调用onTouchEvent,返回true,则调用onTouchEvent。
滑动冲突主要分为「同方向」和「不同方向」的滑动冲突。 解决滑动冲突的关键就是明确告接收Touch的View是否需要拦截此次事件。
从外部拦截
正常情况下,父控件会优先接收到Touch事件。在onInterceptTouch的根据条件判断。
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
var resume = false
when(ev?.action){
MotionEvent.ACTION_DOWN -> {
resume = false
}
MotionEvent.ACTION_MOVE -> {
if (...){
resume = false
}else{
resume = true
}
}
...
}
return resume
}
从内部拦截
从内部拦截,需要调用子View.getParent().requestDisallowInterceptTouchEvent(true) 来影响外部父控件的事件接收。
doRequestData.setOnTouchListener(object:View.OnTouchListener{
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
// 传入true,则parent不拦截
doRequestData.parent.requestDisallowInterceptTouchEvent(true)
when(event?.action){
MotionEvent.ACTION_DOWN -> {}
MotionEvent.ACTION_MOVE -> {
if(...){
// 传入false,parent进行拦截
doRequestData.parent.requestDisallowInterceptTouchEvent(false)
} else {
doRequestData.parent.requestDisallowInterceptTouchEvent(true)
}
}
...
}
return false
}
})