文章目录
分析来自Android8.1.0源码
DecorView的Touch事件处理
我们现在先关注View相关的事件处理,先不关心如何到达View的。后面还会分析如何到达View。
我们先从DecorView的Touch事件处理开始
public class DecorView {
private PhoneWindow mWindow;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
}
- 获取
PhoneWindow
对象的Callback
对象。PhoneWindow
是在Activity
的attach
方法中创建的,并且Activity
实现了Window.Callback
,并传递给PhoneWindow
作为Callback
的回调。 - 如果不
cb
为null
,cb
没有被销毁,mFeatureId
小于0就会执行Window.Callback
对象的dispatchTouchEvent
方法。Activity
运行时,前两个满足,当创建Activity
的时候mFeatureId
实际为-1。所以会调用Window.Callback
对象的dispatchTouchEvent
方法,也就是Activity
实现的方法。
Activity中的Touch事件处理函数
有touch事件来的时候,会调用Activity的dispatchTouchEvent()派发事件,然后会调用getWindow().superDispatchTouchEvent(ev)派发事件,最终会调用布局中的View.
public class Activity extends ContextThemeWrapper
implements Window.Callback {
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
}
- 如果是
MotionEvent.ACTION_DOWN
会调用onUserInteraction
接口 - 获取
Window
对象,实际为PhoneWindow
对象。并调用其superDispatchTouchEvent
方法,如果处理了直接返回true
, - 如果
Window
对象调用superDispatchTouchEvent
没有处理事件,就直接调用Activity
的onTouchEvent
方法。
因为Window
对象实际为PhoneWindow
对象,我们继续分析一下PhoneWindow
的superDispatchTouchEvent
方法。
PhoneWindow对象superDispatchTouchEvent
public class PhoneWindow extends Window {
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
}
将会调用DecorView
的superDispatchTouchEvent
public class DecorView extends FrameLayout {
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
}
最后会调用父类的dispatchTouchEvent
方法
FrametLaout
继承ViewGroup
,ViewGroup
继承自View
,并复写了View的dispatchTouchEvent
方法。
总结:Activity
的Touch
会调用到PhoneWindow
的superDispatchTouchEvent
方法处理Touch
事件,PhoneWindow
又交由DecorView
的superDispatchTouchEvent
方法处理,DecorView
会调用其父类的dispatchTouchEvent
来处理,也就是ViewGroup
的dispatchTouchEvent
来处理。
下面我们在分析ViewGroup
的dispatchTouchEvent
之前我们先来分析一下View
的dispatchTouchEvent
处理
View的Touch事件处理特性
View
中的Touch
事件一个是View
控件的Touch
事件处理,一个是ViewGroup
控件的Touch
事件处理,二者处理方式有所不同ViewGroup
的Touch
事件处理是先由子View
控件处理,子View
控件没有消耗,然后有父View控件进行处理.- 对于
ViewGroup
控件可以通过onInterceptTouchEvent
的方法拦截Touch
事件 View
中的Touch
事件处理会先调用dispatchTouchEvent
分发,然后调用onTouch
处理,未处理会调用onTouchEvent
处理。View控件还是ViewGroup控件处理逻辑都是一致
View控件的Touch事件处理
View
处理Touch
事件时首先被调用的是dispatchTouchEvent()
,此方法的主要工作是调用恰当的方法进行处理.
public class View{
public boolean dispatchTouchEvent(MotionEvent event) {
......
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
......
}
}
先调用onFilterTouchEventForSecurity
方法是否需要过滤事件,我们先来看一下此方法。
public class View {
public boolean onFilterTouchEventForSecurity(MotionEvent event) {
//noinspection RedundantIfStatement
if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
&& (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
// Window is obscured, drop this touch.
return false;
}
return true;
}
}
检查View
和Window
是否被遮盖,如果被遮盖就过滤掉事件。
接着我们继续分析dispatchTouchEvent
方法。
public class View{
public boolean dispatchTouchEvent(MotionEvent event) {
......
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
......
}
......
}
}
接着检查ENABLED_MASK
,也就是View
检查是否enable
,因为只有enable
的状态下的View
才能处理事件。接着调用handleScrollBarDragging
方法,也就是处理滑动scroll bar事件,如果是,result
为true
。
我们继续分析。