系列专栏:
本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;
网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,更有专栏内容免费技术答疑。助您提高安卓面试准备效率,为您面试保驾护航!
事件分发机制属于安卓基础面试必问题目之一。最关键是理解事件分发三个函数的作用和返回值的含义,就基本足够应付面试了。面试官可能会问:
看完以下的解析,一定可以让面试官眼前一亮。
在《Activity、Window、DecorView以及ViewRoot层级关系全解析》一节有下图:
我们知道View的结构是树形结构,View可以放在ViewGroup中,ViewGroup也可以放在另一个ViewGroup中,如此就形成了层层嵌套的关系。当我们触摸到屏幕后,就会生成一个Touch事件,常见的Touch事件有:
Activity/Window --> ViewGroup --> View
其中,View就是各种控件,如Button、TextView等,而ViewGroup是View的子类,因此本质上也是一个View,只不过ViewGroup可以包含多个子View和定义布局参数。
有以下3个重要方法是必须掌握的:
为了更好的了解三者的关系,我们从源码出发,首先看看ViewGroup的dispatchTouchEvent(),源码是Android9.0.0=》/frameworks/base/core/java/android/view/ViewGroup.java:
public boolean dispatchTouchEvent(MotionEvent ev) {
...
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev); //1
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
...
if (actionMasked == MotionEvent.ACTION_DOWN
|| (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
|| actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
...
if (newTouchTarget == null && childrenCount != 0) {
...
for (int i = childrenCount - 1; i >= 0; i--) { //2:遍历ViewGroup的子View
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
...
resetCancelNextUpFlag(child);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) { //3
...
break;
}
...
}
}
}
}
在[注释1]调用了onInterceptTouchEvent()方法来判断是否要拦截当前的事件。
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
&& ev.getAction() == MotionEvent.ACTION_DOWN
&& ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
&& isOnScrollbarThumb(ev.getX(), ev.getY())) {
return true;
}
return false;
}
可以看出onInterceptTouchEvent()默认返回false,代表不拦截。接着在[注释2]遍历ViewGroup的子View,如果子View可以接收到触摸事件,则会执行[注释3]dispatchTransformedTouchEvent():
private boolean dispatchTransformedTouchEvent(