欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android View的onTouchEvent方法与onTouchListener接口的onTouch方法优先级

程序员文章站 2022-08-14 11:45:01
Android View的onTouchEvent方法与onTouchListener接口的onTouch方法优先级onTouchListener接口及其onTouch方法onTouchEvent方法优先级onTouchListener接口及其onTouch方法onTouchListener是View内部定义的一个接口,下面是onTouchListener源码: /** * Interface definition for a callback to be invoked when a...

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