Android事件分发学习笔记

1.大致单线流程
起点—>Activity的dispatchTouchEvent(不是由java层调用的.由C++.Activity驱动去做的.做完之后首先调用这里)

    /**
     * 屏幕触控事件分发Java层入口
     * 不是由java层调用的.由C层Activity驱动去做的.做完之后首先调用这里
     * 调用来处理触摸屏事件。您可以将此重写为在将所有触摸屏事件发送到窗口
     * 请务必将此实现称为触摸屏事件应该正常处理。
     * @param ev 触摸屏事件.
     * @return boolean 返回 true 该事件被消耗.
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            //按下的时候提供用户调用的业务
            onUserInteraction();//这里面什么都没有
        }
        //这里的getWindow就是获取的抽象类Window的子类PhoneWindow
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        return onTouchEvent(ev);
    }

途经—>PhoneWindow的superDispatchTouchEvent(ev)

    public boolean superDispatchTouchEvent(MotionEvent event) {
        //DecorView--->superDispatchTouchEvent(event)
        return mDecor.superDispatchTouchEvent(event);
    }

途经—>DecorView的superDispatchTouchEvent(event)

    public boolean superDispatchTouchEvent(MotionEvent event) {
        //ViewGroup--->dispatchTouchEvent(event)
        return super.dispatchTouchEvent(event);
    }

途经—>ViewGroup的dispatchTouchEvent(event) 核心功能

    /**
     * 事件分发的核心功能就是这里面做的事情
     * */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //辅助功能、残障、跨进程
        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
        }

        ...

        ---------↓↓↓---------
         1.辅助功能、残障
         2.是否启用拦截器(通过设置ViewGroup的requestDisallowInterceptTouchEvent(true)实现拦截)
                   2.1.拦截--->super.dispatchTouchEvent,(super代表自己的View,自己消费掉,不给childView)
                   2.2.不拦截--->找到需要响应的子view.dispatchTouchEvent(view代表下面子View)
                   总结:设置拦截代表拦截子view的触摸事件分发,不设置拦截则可让触控分发到下面的子view
         (不拦截情况下第一次执行:如第一次按下--->直接分发给childView)
         2.2.1.获取到当前操作点下面的所有子View,按View层级排列,取出顶层View
         2.2.2.顶层View.dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)事件开始分发
         2.2.3.if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {}
         (不拦截情况下第二次执行:如第一次按下之后的拖动--->等待判断后再决定是否分发给childView)
         if(!childView.OnTouch的return返回值){<---这里比较第一次多了一个判断
               2.2.1.获取到当前操作点下面的所有子View,按View层级排列,取出顶层View
               2.2.2.顶层View.dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)事件开始分发
               2.2.3.if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {}
         } else {
               执行2.1拦截业务
         }
         总结:
               1.其实我们设置的view.setOnTouchListener的onTouch()的return为false则表示还需要分发给我,下次可以响应继续onTouch,
               2.其实我们设置的view.setOnTouchListener的onTouch()的return为true则表示我不需要分发给我了,下次别来了,你自己处理把,就是等用于我设置了我自己的拦截,执行2.1
        所有的功能有很多.这里只是把核心的分发机制记录一下
        ---------↑↑↑---------

        ...

        if (!handled && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
        }
        return handled;
    }

    
    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,View child, int desiredPointerIdBits) {
       ...
        //调子View--->dispatchTouchEvent(event)
        handled = child.dispatchTouchEvent(event);
       ...
    }

途经—>View—>dispatchTouchEvent(event)

  public boolean dispatchTouchEvent(MotionEvent event) {
      ...
      //li.mOnTouchListener.onTouch(this, event):调用我们对View设置的setOnTouchListener(listener)
      if (li != null && li.mOnTouchListener != null&& (mViewFlags & ENABLED_MASK) == ENABLED&& li.mOnTouchListener.onTouch(this, event)) {
                result = true;
      }

      //上边当调用我们设置的OnTouchListener的onTouch返回=true时下边的onTouchEvent(event)就不会调用
      if (!result && onTouchEvent(event)) {
               result = true;
      }
      ...
  }

  public boolean onTouchEvent(MotionEvent event) {
       ...以下伪代码:View的 单击、长按 ...等 都是在这里分发调用的
       switch(event.getAction()){
            case:MotionEvent.ACTION_UP:
                   break;
            case:MotionEvent.ACTION_DOWN:
                   break;
            case:MotionEvent.ACTION_MOVE:
                   break;
            case:MotionEvent.ACTION_CANCEL:
                   break;
       }
       ...
  }

终点—>setOnTouchListener(listener)的listener
至此成功调用用户设置OnTouchListener的—>OnTouch()

归纳:Activity—>PhoneWindow—>DecorView—>ViewGroup—>View—>我们设置在View上的OnTouchListener

    原文作者:Windows_XP
    原文地址: https://www.jianshu.com/p/de20d2bcb4af
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞