事件分发全面认识
程序员文章站
2022-05-14 15:26:27
...
事件分发全面认识(转自–>)
1.事件在哪些对象之间进行传递?
- Activity(Window) – > ViewGroup – > View
2. 事件的组成元素
-
方法:dispatchTouchEvent()
- 作用: 分发点击事件
- 调用时刻: 当点击事件能够传递给当前View时,该方法被调用.
- return true:
- 消费事件
- 事件不会往下传递
- 后续事件(Move Up)会继续分发到该View
- return false
- 不消费事件
- 事件不会往下传递
- 将事件回传给父控件的onTouchEvent()处理
- Activity例外: 返回false = 消费事件
- 后续事件(Move Up)会继续分发到该View.
-
方法:onInterceptTouchEvent()
- 作用: 判断是否拦截了某个事件
- 调用时刻: 在dispatchTouchEvent()内部调用.
- return true
- 拦截事件
- 事件不会往下传递.
- 自己处理,执行自己的onTouchEvent事件.
- return fals
- 不拦截事件
- 事件会继续往下传递
- 事件传递到子View,调用父类View.dispatchTouchEvent()方法
- 当前View仍然接受此事件的其他事件.
-
方法: onTouchEvent()
- 作用:处理点击事件
- 调用时刻: 在dispatchTouchEvent()内部调用.
- return true
- 自己处理(消费)该事件
- 事件停止传递
- 该事件序列的后续事件(Move Up)让其处理.
- return false(默认实现,调用父类onTouchEvent)
- 不处理(消费)该事件
- 事件往上传递给父控件的onTouchEvent()处理
- 当前View不再接受此事件的其他事件.
- 返回值不同: 常见问题--> move up事件失效.
3. 场景分析
- 最外层:Activity A 包含两个子View: ViewGroup B View C
- 中间层: ViewGroup B, 包含一个子View: View C.
- 最内层: View C.
- 默认事件传递
- A – > B – > C, 从上往下调用dispatchTouchEvent()
- C – > B – > A, 从下往上调用onTouchEvnet()
- 处理事件(C处理点击事件)
- Down事件被传递给C的onTouchEvent方法.返回true,表示处理该事件.
- C处理这个事件,Down事件不再传递给B和A的onTouchEvent()
- Move Up事件传递给C的onTouchEvent().
- 拦截down事件(B希望处理这个点击事件)
- DOWN事件被传递给B的onInterceptTouchEvent()方法,该方法返回true,
表示拦截这个事件,即自己处理这个事件(不再往下传递). - 调用onTouchEvent()处理事件(DOWN事件将不再往上传递给A的onTouchEvent()).
- 该事件列的其他事件(Move、Up)将直接传递给B的onTouchEvent().
- Move Up其他事件不会在传递给B. 该方法一旦返回true,就再也不会返回被调用.
- DOWN事件被传递给B的onInterceptTouchEvent()方法,该方法返回true,
- 拦截Down的后续事件(拦截Move事件)
- 假设ViewGroup B没有拦截DOWN事件(还是View C来处理DOWN事件),但它拦截了接下来的MOVE事件。
- DOWN事件传递到C的onTouchEvent方法,返回了true。
- 在后续到来的MOVE事件,B的onInterceptTouchEvent方法返回true拦截该MOVE事件,
但该事件并没有传递给B;这个MOVE事件将会被系统变成一个CANCEL事件传递给C的onTouchEvent方法. - 后续又来了一个MOVE事件,该MOVE事件才会直接传递给B的onTouchEvent().
- C再也不会收到该事件列产生的后续事件。
- 假设ViewGroup B没有拦截DOWN事件(还是View C来处理DOWN事件),但它拦截了接下来的MOVE事件。
4. 源码分析
- Activity对点击事件的分发机制.
- ViewGroup对点击事件的分发机制.
- View对点击事件的分发机制.
Activity的dispatchTouchEvent()
/**
* Called to process touch screen events. You can override this to
* intercept all touch screen events before they are dispatched to the
* window. Be sure to call this implementation for touch screen events
* that should be handled normally.
*
* @param ev The touch screen event.
*
* @return boolean Return true if this event was consumed.
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();//用于屏保
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;//注解①
}
return onTouchEvent(ev);
- 注解①
- Window类是抽象类,且PhoneWindow是Window类的唯一实现类.
- superDispatchTouchEvent(ev)是抽象方法,返回的是一个Window对象.
- 通过PhoneWindow类中看一下superDispatchTouchEvent()的作用.
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
//mDecor是DecorView的实例
//DecorView是视图的顶层view,继承自FrameLayout,是所有界面的父类
}
待续...