Touch消息传到机制

触摸事件

  • 从Activity的dispatchTouchEvent()进行分析。

触摸事件概念

  • 触摸事件是由一个触摸按下事件、N个触摸滑动事件和一个触摸抬起事件组成的,通常的一个触摸事件中只能存在一个触摸按下和一个触摸抬起事件,但是触摸滑动事件可以有零个或者多个。

好了,知道这个概念以后,下面我们就具体看一下Activity中的dispatchTouchEvent的实现逻辑。

首先会判断是否是按下事件,是,则执行onUserInteraction()方法,而onUserInteraction()方法有执行什么逻辑呢?

public void onUserInteraction() {
}

可以看见它只是Activity中一个空方法,通过方法介绍:

Called whenever a key, touch, or trackball event is dispatched to the activity. Implement this method if you wish to know that the user has interacted with the device in some way while your activity is running. This callback and {@link #onUserLeaveHint} are intended to help activities manage status bar notifications intelligently; specifically, for helping activities determine the proper time to cancel a notfication.

理解上就是用户在触屏点击,按home,back,menu键都会触发此方法。
回到Activity的disaptchTouchEvent()方法中,调用了getWindow().superDispatchTouchEvent(ev)方法,而getWindown()返回的mWindown实例,其实就是phoneWidown对象。这里superDispatchTouchEvent()返回true,则直接返回true,不会再执行onTouchEvent()方法,反之,继续执行onTouchEvent().我们继续看下getWindow().superDispatchTouchEvent(ev)方法:

@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
    return mDecor.superDispatchTouchEvent(event);
}

可以看到继续调用了mDecor.superDispatchTouchEvent方法,而mDecor是我们Activity显示ViewTree的根View,并且mdecor是FrameLayout的一个子类,DecorView是phoneWindow中一个final内部类,是window界面的最顶层View.

View的DispatchTouEvent()

  • View 的dispatchTouchEvent()源码如下:

有图可知onTouch()是优于onTouchEvent()执行的,但是Ontouch()执行的前提是控件enable属性是为true并且mOnTouchlistener不为空,ontouch()才会执行;而且可知ontouch()放回true,ontouchEvent()将不会再执行
* View的onTouchEvent()方法:


    public boolean onTouchEvent(MotionEvent event) {  
          final int viewFlags = mViewFlags;  
      //如果View是disable并且View是可以点击或长按的直接返回true,表示该View一直消费Touch事件
          if ((viewFlags & ENABLED_MASK) == DISABLED) {  
              return (((viewFlags & CLICKABLE) == CLICKABLE ||  
                      (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));  
          }  

          //如果设置了Touch代理,就交给代理来处理,mTouchDelegate默认是null  
          if (mTouchDelegate != null) {  
              if (mTouchDelegate.onTouchEvent(event)) {  
                  return true;  
              }  
          }  

          //如果View是clickable或者longClickable的onTouchEvent就返回true, 否则返回false  
          if (((viewFlags & CLICKABLE) == CLICKABLE ||  
                  (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {  
              switch (event.getAction()) {  
                  case MotionEvent.ACTION_UP:  
                      boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;  
                      if ((mPrivateFlags & PRESSED) != 0 || prepressed) {  
                          boolean focusTaken = false;  
                          if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {  
                              focusTaken = requestFocus();  
                          }  

                          if (!mHasPerformedLongPress) {  
                              removeLongPressCallback();  

                              if (!focusTaken) {  
                                  if (mPerformClick == null) {  
                                      mPerformClick = new PerformClick();  
                                  }  
                                  if (!post(mPerformClick)) {  
                                      performClick();  
                                  }  
                              }  
                          }  

                          if (mUnsetPressedState == null) {  
                              mUnsetPressedState = new UnsetPressedState();  
                          }  

                          if (prepressed) {  
                              mPrivateFlags |= PRESSED;  
                              refreshDrawableState();  
                              postDelayed(mUnsetPressedState,  
                                      ViewConfiguration.getPressedStateDuration());  
                          } else if (!post(mUnsetPressedState)) {  
                              mUnsetPressedState.run();  
                          }  
                          removeTapCallback();  
                      }  
                      break;  

                  case MotionEvent.ACTION_DOWN:  
                      if (mPendingCheckForTap == null) {  
                          mPendingCheckForTap = new CheckForTap();  
                      }  
                      mPrivateFlags |= PREPRESSED;  
                      mHasPerformedLongPress = false;  
                      postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());  
                      break;  

                  case MotionEvent.ACTION_CANCEL:  
                      mPrivateFlags &= ~PRESSED;  
                      refreshDrawableState();  
                      removeTapCallback();  
                      break;  

                  case MotionEvent.ACTION_MOVE:  
                      final int x = (int) event.getX();  
                      final int y = (int) event.getY();  

                      //当手指在View上面滑动超过View的边界,  
                      int slop = mTouchSlop;  
                      if ((x < 0 - slop) || (x >= getWidth() + slop) ||  
                              (y < 0 - slop) || (y >= getHeight() + slop)) {  
                          // Outside button  
                          removeTapCallback();  
                          if ((mPrivateFlags & PRESSED) != 0) {  
                              removeLongPressCallback();  

                              mPrivateFlags &= ~PRESSED;  
                              refreshDrawableState();  
                          }  
                      }  
                      break;  
              }  
              return true;  
          }  

          return false;  
      }  

  • 有onTouchEvent()源码分析我们可以知道:

    1. 如果一个View是disable的并且该View是可以点击或者长按的,ontouChEvent直接返回true,表示该View一直消费touch事件。
    2. 如果一个View是enable的,并且是clickable的或longclickable,onTouchEvent()会执行下面的逻辑并返回true;
    3. 综合1、2可知一个View是clickable或者longclickable的,会一直消费touch事件的
    4. 而普通的View(既不是clickable也不是longclickable)不会消费touch事件(只会执行action_down,而不会执行action_move和action_up)

ViewGroup的dispatchTouchEvent()

  • 当你点击了任何控件,首先会去调用该控件所在布局的dispatchTouchEvent(),然后找到所在布局dispatchTouchEvent()中找到相应被点击的控件,在调用相应控件的dispatchTouchEvent().

            @Override  
         public boolean dispatchTouchEvent(MotionEvent ev) {  
           final int action = ev.getAction();  
           final float xf = ev.getX();  
           final float yf = ev.getY();  
           final float scrolledXFloat = xf + mScrollX;  
           final float scrolledYFloat = yf + mScrollY;  
           final Rect frame = mTempRect;  

           //这个值默认是false, 然后我们可以通过requestDisallowInterceptTouchEvent(boolean disallowIntercept)方法  
           //来改变disallowIntercept的值  
           boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  

           //这里是ACTION_DOWN的处理逻辑  
           if (action == MotionEvent.ACTION_DOWN) {  
            //清除mMotionTarget, 每次ACTION_DOWN都很设置mMotionTarget为null  
               if (mMotionTarget != null) {  
                   mMotionTarget = null;  
               }  

               //disallowIntercept默认是false, 就看ViewGroup的onInterceptTouchEvent()方法  
               if (disallowIntercept || !onInterceptTouchEvent(ev)) {  
                   ev.setAction(MotionEvent.ACTION_DOWN);  
                   final int scrolledXInt = (int) scrolledXFloat;  
                   final int scrolledYInt = (int) scrolledYFloat;  
                   final View[] children = mChildren;  
                   final int count = mChildrenCount;  
                   //遍历其子View  
                   for (int i = count - 1; i >= 0; i--) {  
                       final View child = children[i];  

                       //如果该子View是VISIBLE或者该子View正在执行动画, 表示该View才  
                       //可以接受到Touch事件  
                       if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE  
                               || child.getAnimation() != null) {  
                        //获取子View的位置范围  
                           child.getHitRect(frame);  

                           //如Touch到屏幕上的点在该子View上面  
                           if (frame.contains(scrolledXInt, scrolledYInt)) {  
                               // offset the event to the view's coordinate system  
                               final float xc = scrolledXFloat - child.mLeft;  
                               final float yc = scrolledYFloat - child.mTop;  
                               ev.setLocation(xc, yc);  
                               child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  

                               //调用该子View的dispatchTouchEvent()方法  
                               if (child.dispatchTouchEvent(ev))  {  
                                   // 如果child.dispatchTouchEvent(ev)返回true表示  
                                //该事件被消费了,设置mMotionTarget为该子View  
                                   mMotionTarget = child;  
                                   //直接返回true  
                                   return true;  
                               }  
                               // The event didn't get handled, try the next view.  
                               // Don't reset the event's location, it's not  
                               // necessary here.  
                           }  
                       }  
                   }  
               }  
           }  

           //判断是否为ACTION_UP或者ACTION_CANCEL  
           boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||  
                   (action == MotionEvent.ACTION_CANCEL);  

           if (isUpOrCancel) {  
               //如果是ACTION_UP或者ACTION_CANCEL, 将disallowIntercept设置为默认的false  
            //假如我们调用了requestDisallowInterceptTouchEvent()方法来设置disallowIntercept为true  
            //当我们抬起手指或者取消Touch事件的时候要将disallowIntercept重置为false  
            //所以说上面的disallowIntercept默认在我们每次ACTION_DOWN的时候都是false  
               mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;  
           }  

           // The event wasn't an ACTION_DOWN, dispatch it to our target if  
           // we have one.  
           final View target = mMotionTarget;  
           //mMotionTarget为null意味着没有找到消费Touch事件的View, 所以我们需要调用ViewGroup父类的  
           //dispatchTouchEvent()方法,也就是View的dispatchTouchEvent()方法  
           if (target == null) {  
               // We don't have a target, this means we're handling the  
               // event as a regular view.  
               ev.setLocation(xf, yf);  
               if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {  
                   ev.setAction(MotionEvent.ACTION_CANCEL);  
                   mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
               }  
               return super.dispatchTouchEvent(ev);  
           }  

           //这个if里面的代码ACTION_DOWN不会执行,只有ACTION_MOVE  
           //ACTION_UP才会走到这里, 假如在ACTION_MOVE或者ACTION_UP拦截的  
           //Touch事件, 将ACTION_CANCEL派发给target,然后直接返回true  
           //表示消费了此Touch事件  
           if (!disallowIntercept && onInterceptTouchEvent(ev)) {  
               final float xc = scrolledXFloat - (float) target.mLeft;  
               final float yc = scrolledYFloat - (float) target.mTop;  
               mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
               ev.setAction(MotionEvent.ACTION_CANCEL);  
               ev.setLocation(xc, yc);  

               if (!target.dispatchTouchEvent(ev)) {  
               }  
               // clear the target  
               mMotionTarget = null;  
               // Don't dispatch this event to our own view, because we already  
               // saw it when intercepting; we just want to give the following  
               // event to the normal onTouchEvent().  
               return true;  
           }  

           if (isUpOrCancel) {  
               mMotionTarget = null;  
           }  

           // finally offset the event to the target's coordinate system and  
           // dispatch the event.  
           final float xc = scrolledXFloat - (float) target.mLeft;  
           final float yc = scrolledYFloat - (float) target.mTop;  
           ev.setLocation(xc, yc);  

           if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {  
               ev.setAction(MotionEvent.ACTION_CANCEL);  
               target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;  
               mMotionTarget = null;  
           }  

           //如果没有拦截ACTION_MOVE, ACTION_DOWN的话,直接将Touch事件派发给target  
           return target.dispatchTouchEvent(ev);  
      }

整个ViewGroup的事件分发流程:

  1. Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View的。

  2. 在ViewGroup中可以通过onInterceptTouchEvent方法对事件传递进行拦截,onInterceptTouchEvent方法返回true代表不允许事件继续向子View传递,返回false代表不对事件进行拦截,默认返回false。

  3. 子View中如果将传递的事件消费掉,ViewGroup中将无法接收到任何事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
蛋白质是生物体中普遍存在的一类重要生物大分子,由天然氨基酸通过肽键连接而成。它具有复杂的分子结构和特定的生物功能,是表达生物遗传性状的一类主要物质。 蛋白质的结构可分为四级:一级结构是组成蛋白质多肽链的线性氨基酸序列;二级结构是依靠不同氨基酸之间的C=O和N-H基团间的氢键形成的稳定结构,主要为α螺旋和β折叠;三级结构是通过多个二级结构元素在三维空间的排列所形成的一个蛋白质分子的三维结构;四级结构用于描述由不同多肽链(亚基)间相互作用形成具有功能的蛋白质复合物分子。 蛋白质在生物体内具有多种功能,包括提供能量、维持电解质平衡、信息交流、构成人的身体以及免疫等。例如,蛋白质分解可以为人体提供能量,每克蛋白质能产生4千卡的热能;血液里的蛋白质能帮助维持体内的酸碱平衡和血液的渗透压;蛋白质是组成人体器官组织的重要物质,可以修复受损的器官功能,以及维持细胞的生长和更新;蛋白质也是构成多种生理活性的物质,如免疫球蛋白,具有维持机体正常免疫功能的作用。 蛋白质的合成是指生物按照从脱氧核糖核酸(DNA)转录得到的信使核糖核酸(mRNA)上的遗传信息合成蛋白质的过程。这个过程包括氨基酸的活化、多肽链合成的起始、肽链的延长、肽链的终止和释放以及蛋白质合成后的加工修饰等步骤。 蛋白质降解是指食物中的蛋白质经过蛋白质降解酶的作用降解为多肽和氨基酸然后被人体吸收的过程。这个过程在细胞的生理活动中发挥着极其重要的作用,例如将蛋白质降解后成为小分子的氨基酸,并被循环利用;处理错误折叠的蛋白质以及多余组分,使之降解,以防机体产生错误应答。 总的来说,蛋白质是生物体内不可或缺的一类重要物质,对于维持生物体的正常生理功能具有至关重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值