android事件分发(1):view

1、简述

事件分发 ,是手机对手指触摸事件处理的过程;也就是寻找触摸事件处理者,并进行处理的过程

对于android开发者来说,事件分发没有使用过,也是了解过,其实android的事件分发是分为多个模块操作:硬件检测—framework层事件拦截—window内部处理—ViewGroup处理— View处理;我们常常需要处理过程也就是最后两个,笔者觉得先从view出发,开始撸起

2、基础知识

触摸事件是一系列事件,主要处理的事件ACTION_DOWN、ACTION_MOVE、ACTION_CANCEL、ACTION_UP、ACTION_POINTER_DOWN、ACTION_POINTER_UP,事件是以ACTION_DOWN开始,以ACTION_UP或者ACTION_CANCEL事件结束

ACTION_DOWN ----> 其它事件 -----> ACTION_UP/ACTION_CANCEL

2.1 事件类型

ACTION_DOWN : 第一个手指按下事件
ACTION_UP: 最后一个手指抬起事件
ACTION_CANCEL:取消事件,也即是不能得到后续事件
ACTION_MOVE : 移动事件
ACTION_POINTER_DOWN:多个手指时按下事件
ACTION_POINTER_UP:多个手指时,抬起事件

对于触摸事件,响应动作,有回调和监听

2.2 常用处理动作

View.OnTouchListener: 触摸监听
View.OnClickListener: 单击事件监听
View.OnLongClickListener: 长按事件监听
View.onTouchEvent:事件处理回调

2.3 view事件处理方法

dispatchTouchEvent(MotionEvent ev): 事件处理开始方法
onInterceptTouchEvent(MotionEvent ev):在 dispatchTouchEvent方法内调度,拦截事件,ViewGroup内方法
onTouchEvent(MotionEvent event):回调事件处理方法

3、具体处理流程

对于处理流程,我们从View源码中dispatchTouchEvent方法分析,只分析了我认为有用的信息

3.1 dispatchTouchEvent

       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;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

可以看出

  • 有个安全策略,如果满足,则view可以继续处理,否则我们不用管(mInputEventConsistencyVerifier是个不可变量);
  • view处理事件首先查看有没有OnTouchListener对象,存在的话进行处理,处理结果为true,则流程结束
  • OnTouchListener对象为空或者处理结果为false,则调用回调方法onTouchEvent

重点:OnTouchListener监听一定会执行,如若处理结果为false,则onTouchEvent才会执行

3.2 onTouchEvent

有没有问咋没有onInterceptTouchEvent方法,view没有这个方法

  1. TouchDelegate对象处理
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }

可以通过下面方法设置

   public void setTouchDelegate(TouchDelegate delegate) {
        mTouchDelegate = delegate;
    }
  1. ACTION_DOWN 事件处理
           case MotionEvent.ACTION_DOWN:
                    if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {
                        mPrivateFlags3 |= PFLAG3_FINGER_DOWN;
                    }
                    mHasPerformedLongPress = false;
                    if (!clickable) {
                        checkForLongClick( ViewConfiguration.getLongPressTimeout(), x,y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
                        break;
                    }
                    if (performButtonActionOnTouchDown(event)) {
                        break;
                    }
                   
                    boolean isInScrollingContainer = isInScrollingContainer();

                 
                    if (isInScrollingContainer) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        setPressed(true, x, y);
                        checkForLongClick( ViewConfiguration.getLongPressTimeout(),x, y,TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS);
                    }
                    break;
  • checkForLongClick:检测长按事件,通过handler的postDelay延迟执行和remove来取消执行, 执行的长按任务为CheckForLongPress对象,其中执行了OnLongClickListener监听
     public void run() {
            if ((mOriginalPressedState == isPressed()) && (mParent != null)
                    && mOriginalWindowAttachCount == mWindowAttachCount) {
                recordGestureClassification(mClassification);
                if (performLongClick(mX, mY)) { // performLongClick 方法中执行了 OnLongClickListener
                    mHasPerformedLongPress = true;
                }
            }
        }
  1. ACTION_UP关键代码分析
                       if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
                            // This is a tap, so remove the longpress check
                            removeLongPressCallback();

                            // Only perform take click actions if we were in the pressed state
                            if (!focusTaken) {
                                // Use a Runnable and post this rather than calling
                                // performClick directly. This lets other visual state
                                // of the view update before click actions start.
                                if (mPerformClick == null) {
                                    mPerformClick = new PerformClick();
                                }
                                if (!post(mPerformClick)) {
                                    performClickInternal();
                                }
                            }
                        }
  • 通过PerformClick对象或者执行performClickInternal方法来回调OnClickListener监听
  1. ACTION_CANCEL事件
               case MotionEvent.ACTION_CANCEL:
                    if (clickable) {
                        setPressed(false);
                    }
                    removeTapCallback();
                    removeLongPressCallback();
                    mInContextButtonPress = false;
                    mHasPerformedLongPress = false;
                    mIgnoreNextUpEvent = false;
                    mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
                    break;

取消长按事件执行,重置标志

3、流程总结

  • 执行优先级

OnTouchListener.onTouch > onTouchEvent > OnClickListener.onClick or OnLongClickListener.onLongClick

  • 如果事件传到view,那么OnTouchListener.onTouch一定执行;如果执行结果为false,才执行onTouchEvent
  • OnClickListener.onClick or OnLongClickListener.onLongClick是在onTouchEvent方法中执行,且是有且只会执行其中一种

请继续查看 android事件分发(2):ViewGroup

你可能感兴趣的:(android事件分发(1):view)