Android View的onTouchEvent方法与onTouchListener接口的onTouch方法优先级
onTouchListener接口及其onTouch方法
onTouchListener是View内部定义的一个接口,下面是onTouchListener
源码:
/**
* Interface definition for a callback to be invoked when a touch event is
* dispatched to this view. The callback will be invoked before the touch
* event is given to the view.
*/
public interface OnTouchListener {
/**
* Called when a touch event is dispatched to a view. This allows listeners to
* get a chance to respond before the target view.
*
* @param v The view the touch event has been dispatched to.
* @param event The MotionEvent object containing full information about
* the event.
* @return True if the listener has consumed the event, false otherwise.
*/
boolean onTouch(View v, MotionEvent event);
}
可以看到onTouchListener只有一个方法onTouch,onTouch就是我们在外界处理点击事件所要实现的方法。
一般我们在外界处理点击事件时,需要对一个View,例如Button或者TextView,先调用其setOnTouchListener(OnTouchListener l)方法,再传入一个内部匿名监听器new View.onTouchListener(),并实现其onTouch方法,通常我们返回true,true和false是优先级判断的依据之一,下文会解释原因,下面是setOnTouchListener
源码:
/**
* Register a callback to be invoked when a touch event is sent to this view.
* @param l the touch listener to attach to this view
*/
public void setOnTouchListener(OnTouchListener l) {
getListenerInfo().mOnTouchListener = l;
}
可以看到setOnTouchListener方法将我们传入的监听器引用传给了getListenerInfo().mOnTouchListener,下面是getListenerInfo()
源码:
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
可以看到getListenerInfo方法返回的类型是ListenerInfo,而这个ListenerInfo是来自mListenerInfo,也就是说mListenerInfo也是一个ListenerInfo类型,这个逻辑很好理解:如何mListenerInfo为null就new一个新的ListenerInfo(),如果不为null,就直接返回。ListenerInfo是View内部定义的一个类,下面是ListenerInfo
的源码:
static class ListenerInfo {
/**
* Listener used to dispatch focus change events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
@UnsupportedAppUsage
protected OnFocusChangeListener mOnFocusChangeListener;
/**
* Listeners for layout change events.
*/
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
/**
* Listeners for attach events.
*/
private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
/**
* Listener used to dispatch click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
@UnsupportedAppUsage
public OnClickListener mOnClickListener;
/**
* Listener used to dispatch long click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
@UnsupportedAppUsage
protected OnLongClickListener mOnLongClickListener;
/**
* Listener used to dispatch context click events. This field should be made private, so it
* is hidden from the SDK.
* {@hide}
*/
protected OnContextClickListener mOnContextClickListener;
/**
* Listener used to build the context menu.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
*/
@UnsupportedAppUsage
protected OnCreateContextMenuListener mOnCreateContextMenuListener;
@UnsupportedAppUsage
private OnKeyListener mOnKeyListener;
@UnsupportedAppUsage
private OnTouchListener mOnTouchListener;
@UnsupportedAppUsage
private OnHoverListener mOnHoverListener;
@UnsupportedAppUsage
private OnGenericMotionListener mOnGenericMotionListener;
@UnsupportedAppUsage
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
OnCapturedPointerListener mOnCapturedPointerListener;
private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
private WindowInsetsAnimationListener mWindowInsetsAnimationListener;
/**
* This lives here since it's only valid for interactive views.
*/
private List<Rect> mSystemGestureExclusionRects;
/**
* Used to track {@link #mSystemGestureExclusionRects}
*/
public RenderNode.PositionUpdateListener mPositionUpdateListener;
}
通过源码可以看到ListenerInfo类里面保存了很多监听器类型的引用,比如类型为OnTouchListener的mOnTouchListener。
到这里我们就可以发现,每当我们在View的外部通过setOnXXListener方法设置一个监听器时,该方法就将传入的监听器引用保存在ListenerInfo类里面,通过判断此类保存的各种监听器的引用是否为空,就可以判断外界是否对View设置了监听器,这个是后面优先级的判断标准之一。
onTouchEvent方法
onTouchEvent是View内部定义的一个方法,用来处理MotionEvent事件,一般子View(非ViewGroup)返回true,表示这个View已经成功消费了该点击事件,上级View不需要再处理,是一个责任链模式,具体涉及到Android事件分发机制。
优先级
View(非ViewGroup)的事件处理在dispatchTouchEvent中进行,一般返回false,表示最底层的View不能够再往下分发传递MotionEvent事件了,因为最底层的View已经是View树结构最下面的叶节点了,其下没有其他View。
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
\\省略一大堆fucking code
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;
}
}
\\省略一大堆fucking code
return result;
}
可以看到首先通过li.mOnTouchListener(li就是上文介绍的保存了所有外部监听器的ListenerInfo类)查看是否设置了外部点击事件监听器,如果没有设置就直接跳到onTouchEvent执行相应处理。如果设置了外部监听器,再根据监听器处理结果的返回值进行判断:返回true,result为true;返回false,result为false。当result为true时,if (!result && onTouchEvent(event))判定条件后面的onTouchEvent不会执行。
综上
当设置的匿名监听器的onTouch方法返回值为true时,View的onTouchEvent方法不执行;
当设置的匿名监听器的onTouch方法返回值为false时,View的onTouchEvent方法执行。
本文地址:https://blog.csdn.net/Wang_Ritian/article/details/108977493