资讯专栏INFORMATION COLUMN

ViewGroup源码-Touch事件

rozbo / 3377人阅读

摘要:在中查看源码在看完源码的触摸事件源码事件后,我们接着来看看容器类的触摸事件。同样的先来看源码中的方法首先,会判断是否不允许拦截,可以通过进行设置,默认允许拦截。

在Android-27中查看源码:

在看完View源码的触摸事件(View源码-Touch事件)后,我们接着来看看容器类View的触摸事件。因为容器类的View都继承自ViewGroup,所以我们在ViewGroup的源码中来看看是如何处理触摸事件的。

同样的先来看ViewGroup源码中的dispatchTouchEvent方法:

</>复制代码

  1. final boolean intercepted;
  2. if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
  3. final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
  4. if (!disallowIntercept) {
  5. intercepted = onInterceptTouchEvent(ev);
  6. ev.setAction(action); // restore action in case it was changed
  7. } else {
  8. intercepted = false;
  9. }
  10. } else {
  11. // There are no touch targets and this action is not an initial down
  12. // so this view group continues to intercept touches.
  13. intercepted = true;
  14. }

首先,会判断是否不允许拦截,可以通过requestDisallowInterceptTouchEvent进行设置,默认允许拦截。如果允许拦截,会调用onInterceptTouchEvent,看看该View是否拦截了触摸事件,默认不拦截即可以将触摸事件向子View传递。

接下来,如果触摸事件没有取消并且没有拦截,在手指按下的时候:

</>复制代码

  1. final ArrayList preorderedList = buildTouchDispatchChildList();
  2. ...
  3. for (int i = childrenCount - 1; i >= 0; i--){
  4. ...
  5. newTouchTarget = getTouchTarget(child);
  6. if (newTouchTarget != null) {
  7. // Child is already receiving touch within its bounds.
  8. // Give it the new pointer in addition to the ones it is handling.
  9. newTouchTarget.pointerIdBits |= idBitsToAssign;
  10. break;
  11. }
  12. resetCancelNextUpFlag(child);
  13. if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
  14. // Child wants to receive touch within its bounds.
  15. mLastTouchDownTime = ev.getDownTime();
  16. if (preorderedList != null) {
  17. // childIndex points into presorted list, find original index
  18. for (int j = 0; j < childrenCount; j++) {
  19. if (children[childIndex] == mChildren[j]) {
  20. mLastTouchDownIndex = j;
  21. break;
  22. }
  23. }
  24. } else {
  25. mLastTouchDownIndex = childIndex;
  26. }
  27. mLastTouchDownX = ev.getX();
  28. mLastTouchDownY = ev.getY();
  29. newTouchTarget = addTouchTarget(child, idBitsToAssign);
  30. alreadyDispatchedToNewTouchTarget = true;
  31. break;
  32. }
  33. ...
  34. }

按照绘制子View的顺序,找到该ViewGoup的所有子view,并保存到ArrayList中。

根据视图顺序依次遍历子View。判断当前子view是否是TouchTarget,若是则跳出循环。否则调用dispatchTransformedTouchEvent方法,如果当前子View的dispatchTouchEvent返回为true,找到该子View在ViewGroup中的index,并将该子View作为新的TouchTarget。

清楚保存了所有子View的ArrayList。

然后在TouchTarget形成的链式结构中,处理触摸事件:

</>复制代码

  1. // Dispatch to touch targets.
  2. if (mFirstTouchTarget == null) {
  3. // No touch targets so treat this as an ordinary view.
  4. handled = dispatchTransformedTouchEvent(ev, canceled, null,TouchTarget.ALL_POINTER_IDS);
  5. } else {
  6. // Dispatch to touch targets, excluding the new touch target if we already
  7. // dispatched to it. Cancel touch targets if necessary.
  8. TouchTarget predecessor = null;
  9. TouchTarget target = mFirstTouchTarget;
  10. while (target != null) {
  11. final TouchTarget next = target.next;
  12. if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
  13. handled = true;
  14. } else {
  15. final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
  16. if (dispatchTransformedTouchEvent(ev, cancelChild,target.child, target.pointerIdBits)) {
  17. handled = true;
  18. }
  19. if (cancelChild) {
  20. if (predecessor == null) {
  21. mFirstTouchTarget = next;
  22. } else {
  23. predecessor.next = next;
  24. }
  25. target.recycle();
  26. target = next;
  27. continue;
  28. }
  29. }
  30. predecessor = target;
  31. target = next;
  32. }
  33. }

如果子View没有处理触摸事件,则由当前的ViewGroup处理,然后返回处理结果。因为ViewGroup是View的子类,所以还是由View的dispatchTouchEvent处理。

如果子View中处理了触摸事件,根据TouchTarget生成的链式结构,不断循环,分别调用里面View的dispatchTouchEvent方法。

从上面的分析可以看出整个ViewGroup的Touch事件的整个传递过程如下:

是否调用了requestDisallowInterceptTouchEvent方法设置不允许拦截,默认允许拦截。若允许拦截,则再调用onInterceptTouchEvent,看是否拦截。

如果触摸事件被拦截,则调用ViewGroup的dispatchTransformedTouchEvent方法,其实是调用View的dispatchTouchEvent方法。否则继续向下。

当触摸事件为MotionEvent.ACTION_DOWN时,首先获取根据绘制顺序保存了所有子View的ArrayLsit,然后再根据视图顺序去遍历子View。

如果从TouchTarget形成的链表中发现该View,则跳出循环,即找到了TouchTarget。否则继续向下。

在子View中寻找,当子View的dispatchTouchEvent方法返回为true时,则找到了新的TouchTarget,并将其添加到TouchTarget形成的链表中。

遍历TouchTarget形成的链表,然后对链表里面的子View分别调用dispatchTouchEvent,最后将处理结果返回。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72185.html

相关文章

  • View事件机制分析

    摘要:注意,事件分发是向下传递的,也就是父到子的顺序。事件分发机制的本质是要解决,点击事件由哪个对象发出,经过哪些对象,最终达到哪个对象并最终得到处理。表示以及分发给其中在内部完成被赋值。会自己处理事件。 目录介绍 01.Android中事件分发顺序 1.1 事件分发的对象是谁 1.2 事件分发的本质 1.3 事件在哪些对象间进行传递 1.4 事件分发过程涉及方法 1.5 Androi...

    bergwhite 评论0 收藏0
  • View事件机制源码分析

    摘要:当不拦截事件的时候,事件会向下分发交由它的子或进行处理。表示以及分发给其中在内部完成被赋值。会自己处理事件。 目录介绍 01.Android中事件分发顺序 02.Activity的事件分发机制 2.1 源码分析 2.2 点击事件调用顺序 2.3 得出结论 03.ViewGroup事件的分发机制 3.1 看一下这个案例 3.2 源码分析 3.3 得出结论 04.Vie...

    antz 评论0 收藏0
  • View源码-Touch事件

    摘要:接下来查看方法的源码里面的处理如下如果则返回,即该对触摸事件不予处理。显示了提示框的话则隐藏如果不可点击,则移除长按事件的检测,返回否则继续向下走。当前是点击事件,所以移除长按事件的检测。关于源码中的事件,可以参考文章源码事件 在Android-27中查看源码: 首先我们来查看单个View的触摸事件的处理,在View的dispatchTouchEvent方法中看看源码是如何处理的。 p...

    Barry_Ng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<