前言
在我们的项目中,遇到比较复杂布局的时候,最常见的就是布局嵌套和自定义控件,那么滑动冲突与点击冲突你一定是遇到过的,解决的方法有很多,但是总的来说都是对onTouch事件传递做处理.那么我们就来了解一下onTouch事件到底是怎么传递的
1.基本知识
我们先看看相关的几个方法
(View是没有onInterceptTouchEvent方法的)
ViewGroup
- 1. dispatchTouchEvent(分发touch事件)
- 2. onInterceptTouchEvent(拦截touch事件)
- 3. onTouchEvent(消费事件)
View
- 1. dispatchTouchEvent(分发touch事件)
- 2. onTouchEvent(消费事件)
一个事件首先会由dispatchTouchEvent决定怎么分配,接着由onInterceptTouchEvent决定是否拦截,最后由onTouchEvent决定怎么消费
一般来说我们会重写onInterceptTouchEvent和onTouchEvent方法来改变事件的传递,但是不会去重写dispatchTouchEvent方法
下面为了更好的描述,有些地方就用简称描述了
- dispatchTouchEvent : 分配
- onInterceptTouchEvent : 拦截
2. 传递规律
(1)基本传递方向
首先我们需要知道onTouch事件传递的基本传递方向,onTouch事件的传递方向大概是从父控件传递到子控件,然后再从子控件传回父控件,这个过程中一旦事件被消费了,那么事件就不会继续传递了
(2)拦截
onInterceptTouchEvent方法会有一个返回值,如果你返回的是false,表示不拦截,那么事件就会先往子控件传递,如果你返回的是true,表示拦截,那么事件不会往下传递了
(3)消费
可以消费事件的地方有两个:
- OnTouchListener: 通过setOnTouchListener设置的OnTouchListener里面的onTouch方法
- onTouchEvent: 控件本身的onTouchEvent方法
这两个方法都有返回值,如果你返回的是true,代表事件被消费了,如果你返回的是false,那么就算你在方法里做了很多事,也不算消费
当OnTouchListener存在的时候,会先获取到事件,如果不消费的话才会传到onTouchEvent
OnTouchListener虽然优先于onTouchEvent,但都属于同一层的消费,在这里我们就不分开来描述了,统一描述为自己消费
(OnTouchListener > onTouchEvent)
(4)一组事件
move和up事件往往是和dowm事件相关联的,为了简化描述,我们这里就把down,move,up同一称为一组事件(下一次down事件之后的算下一组)
(5)控件
这里指的所有控件都是在onTouch事件的点击范围内,如果不在这个点击范围内的控件,是不会参与事件传递的
3.传递路线
一个控件获取到事件时,首先会走dispatchTouchEvent,才会走onInterceptTouchEvent和onTouchEvent,一般我们都不会去重写dispatchTouchEvent方法(研究源码的需要重点研究这个方法),所以接下来的传递路线就跳过dispatchTouchEvent这个方法了
这个例子里面只有一个ViewGroup,ViewGroup里面有只有一个View
4.要点
(1)拦截
①如果ViewGroup在onInterceptTouchEvent里面拦截了down事件,那么这一组事件都不会再进入onInterceptTouchEvent方法里面了,也不会分配到View里面了
(2)消费
①如果ViewGroup消费了down事件,那么这一组事件不会进入到onInterceptTouchEvent里面了,更不会分配到View里面了,而是直接从dispatchTouchEvent方法走到自己消费的方法里
(3)多个View
如果ViewGroup有多个View,那么会从最上面的view遍历,如果有view消费了down事件,那么就不会继续遍历了,而且这一组事件也会直接进入这个view
(还会走ViewGroup的分配和拦截方法)
5.总结
onTouch事件的传递有很多可能的路线,这里就不贴出笔者当初研究的DEMO代码了,免得看得头晕.你只要知道几个主要的原则和规律,再复杂的情况你也能够知道事件会怎么传递,这里就再次总结一下
(1)一个ViewGroup有三种方法,分配,拦截,消费
- 分配: dispatchTouchEvent
- 拦截: onInterceptTouchEvent
- 消费: OnTouchListener和onTouchEvent (优先走OnTouchListener的onTouch)
(View的话没有拦截)
(2)首先事件会从父控件开始,逐级往下传递
(2)事件经过某个控件的时候,会先走分配,再走拦截,如果不拦截又会接着往下分配
(3)事件从上往下分配时,要么是走到某一层被拦截了,要么是走到最底层了才会停止向下分配
(4)一旦停止向下传递,就要开始考虑消费的事了
(5)从停止传递的那一层开始,询问是否要消费事件,如果自己不消费,那么逐级往上询问
(6)一旦某层把事件消费了,那么就不再向上询问,事件传递就到此结束了
6.思维导图
笔者当初第一次研究的时候做了一个DEMO,并把传递的过程用思维导图详细的记录了下来,有兴趣的朋友可以去下载看看,免费的哦,不过还是建议有时间的朋友能够自己写demo测试一下,这样才能更好的理解.
http://download.csdn.net/download/yulyu/9763226
网友评论