美文网首页Android 高级UI
Android事件分发学习笔记

Android事件分发学习笔记

作者: Windows_XP | 来源:发表于2018-07-23 21:14 被阅读3次

    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

    相关文章

      网友评论

        本文标题:Android事件分发学习笔记

        本文链接:https://www.haomeiwen.com/subject/yrospftx.html