资讯专栏INFORMATION COLUMN

View事件机制源码分析

antz / 1374人阅读

摘要:当不拦截事件的时候,事件会向下分发交由它的子或进行处理。表示以及分发给其中在内部完成被赋值。会自己处理事件。

目录介绍

01.Android中事件分发顺序

02.Activity的事件分发机制

2.1 源码分析

2.2 点击事件调用顺序

2.3 得出结论

03.ViewGroup事件的分发机制

3.1 看一下这个案例

3.2 源码分析

3.3 得出结论

04.View事件的分发机制

4.1 源码分析

4.2 得出结论

4.3 验证结论

05.思考一下

5.1 onTouch()和onTouchEvent()的区别

5.2 Touch事件的后续事件传递

好消息

博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!

链接地址:https://github.com/yangchong2...

如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

View事件系列博客

01.View事件基础

事件分发的对象是谁?事件在哪些对象间进行传递?事件分发过程涉及方法?事件分发机制方法说明?

02.View事件分发场景

事件分发背景描述,事件传递情况

03.View事件机制源码分析

Android中事件分发顺序?Activity的事件分发机制?ViewGroup事件的分发机制 ?View事件的分发机制?onTouch()和onTouchEvent()的区别?

04.View事件机制

触摸事件,分发事件,拦截事件,三个事件机制怎么向其调用者传递处理结果,滑动冲突的思路及方法 ,以及具体的滑动冲突解决方案案例

05.View的滑动冲突

通过一个滑动冲突的案例,来讲解外部拦截法解决滑动冲突,内部拦截法解决滑动冲突

07.View事件总结1

Android事件分发机制,View和ViewGroup分发事件,onTouch()、onTouchEvent()和onClick()执行顺序,View处理事件的优先级,点击事件传递过程,事件传递规则要点

08.View事件总结2

View滑动有哪些方法,Activity事件分发过程,Window事件分发过程,DecorView的事件分发,根View的事件分发

01.Android中事件分发顺序

Android中事件分发顺序:

Activity(Window) -> ViewGroup -> View

其中:

super:调用父类方法

true:消费事件,即事件不继续往下传递

false:不消费事件,事件继续往下传递 / 交由给父控件onTouchEvent()处理

充分理解Android分发机制,本质上是要理解:

Activity对点击事件的分发机制

ViewGroup对点击事件的分发机制

View对点击事件的分发机制

02.Activity的事件分发机制 2.1 源码分析

当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发

具体是由Activity的Window来完成

我们来看下Activity的dispatchTouchEvent()的源码

</>复制代码

  1. public boolean dispatchTouchEvent(MotionEvent ev) {
  2. //第一步
  3. //一般事件列开始都是DOWN,所以这里基本是true
  4. if (ev.getAction() == MotionEvent.ACTION_DOWN) {
  5. //第二步
  6. onUserInteraction();
  7. }
  8. //第三步
  9. if (getWindow().superDispatchTouchEvent(ev)) {
  10. return true;
  11. }
  12. return onTouchEvent(ev);
  13. }

第一步

一般事件列开始都是DOWN(按下按钮),所以这里返回true,执行onUserInteraction()

第二步

先来看下onUserInteraction()源码

</>复制代码

  1. public void onUserInteraction() {
  2. }

从源码可以看出:

该方法为空方法

从注释得知:当此activity在栈顶时,触屏点击按home,back,menu键等都会触发此方法

所以onUserInteraction()主要用于屏保

第三步

Window类是抽象类,且PhoneWindow是Window类的唯一实现类

superDispatchTouchEvent(ev)是抽象方法

通过PhoneWindow类中看一下superDispatchTouchEvent()的作用

</>复制代码

  1. @Override
  2. public boolean superDispatchTouchEvent(MotionEvent event) {
  3. return mDecor.superDispatchTouchEvent(event);
  4. //mDecor是DecorView的实例
  5. //DecorView是视图的顶层view,继承自FrameLayout,是所有界面的父类
  6. }

接下来我们看mDecor.superDispatchTouchEvent(event):

</>复制代码

  1. public boolean superDispatchTouchEvent(MotionEvent event) {
  2. return super.dispatchTouchEvent(event);
  3. //DecorView继承自FrameLayout
  4. //那么它的父类就是ViewGroup
  5. super.dispatchTouchEvent(event)方法,其实就应该是ViewGroup的dispatchTouchEvent()
  6. }

得出结果

执行getWindow().superDispatchTouchEvent(ev)实际上是执行了ViewGroup.dispatchTouchEvent(event)

这样事件就从 Activity 传递到了 ViewGroup

2.2 点击事件调用顺序

当一个点击事件发生时,调用顺序如下

1.事件最先传到Activity的dispatchTouchEvent()进行事件分发

2.调用Window类实现类PhoneWindow的superDispatchTouchEvent()

3.调用DecorView的superDispatchTouchEvent()

4.最终调用DecorView父类的dispatchTouchEvent(),即ViewGroup的dispatchTouchEvent()

2.3 得出结论

当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发,最终是调用了ViewGroup的dispatchTouchEvent()方法

这样事件就从 Activity 传递到了 ViewGroup

03.ViewGroup事件的分发机制 3.1 看一下这个案例

布局如下:

结果测试

只点击Button,发现执行顺序:btn1,btn2

再点击空白处,发现执行顺序:btn1,btn2,viewGroup

从上面的测试结果发现:

当点击Button时,执行Button的onClick(),但ViewGroupLayout注册的onTouch()不会执行

只有点击空白区域时才会执行ViewGroupLayout的onTouch();

结论:Button的onClick()将事件消费掉了,因此事件不会再继续向下传递。

3.2 源码分析

ViewGroup的dispatchTouchEvent()源码分析,该方法比较复杂,截取几个重要的逻辑片段进行介绍,来解析整个分发流程。

</>复制代码

  1. // 发生ACTION_DOWN事件或者已经发生过ACTION_DOWN,并且将mFirstTouchTarget赋值,才进入此区域,主要功能是拦截器
  2. final boolean intercepted;
  3. if (actionMasked == MotionEvent.ACTION_DOWN|| mFirstTouchTarget != null) {
  4. //disallowIntercept:是否禁用事件拦截的功能(默认是false),即不禁用
  5. //可以在子View通过调用requestDisallowInterceptTouchEvent方法对这个值进行修改,不让该View拦截事件
  6. final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
  7. //默认情况下会进入该方法
  8. if (!disallowIntercept) {
  9. //调用拦截方法
  10. intercepted = onInterceptTouchEvent(ev);
  11. ev.setAction(action);
  12. } else {
  13. intercepted = false;
  14. }
  15. } else {
  16. // 当没有触摸targets,且不是down事件时,开始持续拦截触摸。
  17. intercepted = true;
  18. }

这一段的内容主要是为判断是否拦截。如果当前事件的MotionEvent.ACTION_DOWN,则进入判断,调用ViewGroup onInterceptTouchEvent()方法的值,判断是否拦截。如果mFirstTouchTarget != null,即已经发生过MotionEvent.ACTION_DOWN,并且该事件已经有ViewGroup的子View进行处理了,那么也进入判断,调用ViewGroup onInterceptTouchEvent()方法的值,判断是否拦截。如果不是以上两种情况,即已经是MOVE或UP事件了,并且之前的事件没有对象进行处理,则设置成true,开始拦截接下来的所有事件。这也就解释了如果子View的onTouchEvent()方法返回false,那么接下来的一些列事件都不会交给他处理。如果VieGroup的onInterceptTouchEvent()第一次执行为true,则mFirstTouchTarget = null,则也会使得接下来不会调用onInterceptTouchEvent(),直接将拦截设置为true。

当ViewGroup不拦截事件的时候,事件会向下分发交由它的子View或ViewGroup进行处理。

</>复制代码

  1. /* 从最底层的父视图开始遍历,
  2. ** 找寻newTouchTarget,即上面的mFirstTouchTarget
  3. ** 如果已经存在找寻newTouchTarget,说明正在接收触摸事件,则跳出循环。
  4. */
  5. for (int i = childrenCount - 1; i >= 0; i--) {
  6. final int childIndex = customOrder
  7. ? getChildDrawingOrder(childrenCount, i) : i;
  8. final View child = (preorderedList == null)
  9. ? children[childIndex] : preorderedList.get(childIndex);
  10. // 如果当前视图无法获取用户焦点,则跳过本次循环
  11. if (childWithAccessibilityFocus != null) {
  12. if (childWithAccessibilityFocus != child) {
  13. continue;
  14. }
  15. childWithAccessibilityFocus = null;
  16. i = childrenCount - 1;
  17. }
  18. //如果view不可见,或者触摸的坐标点不在view的范围内,则跳过本次循环
  19. if (!canViewReceivePointerEvents(child)
  20. || !isTransformedTouchPointInView(x, y, child, null)) {
  21. ev.setTargetAccessibilityFocus(false);
  22. continue;
  23. }
  24. newTouchTarget = getTouchTarget(child);
  25. // 已经开始接收触摸事件,并退出整个循环。
  26. if (newTouchTarget != null) {
  27. newTouchTarget.pointerIdBits |= idBitsToAssign;
  28. break;
  29. }
  30. //重置取消或抬起标志位
  31. //如果触摸位置在child的区域内,则把事件分发给子View或ViewGroup
  32. if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
  33. // 获取TouchDown的时间点
  34. mLastTouchDownTime = ev.getDownTime();
  35. // 获取TouchDown的Index
  36. if (preorderedList != null) {
  37. for (int j = 0; j < childrenCount; j++) {
  38. if (children[childIndex] == mChildren[j]) {
  39. mLastTouchDownIndex = j;
  40. break;
  41. }
  42. }
  43. } else {
  44. mLastTouchDownIndex = childIndex;
  45. }
  46. //获取TouchDown的x,y坐标
  47. mLastTouchDownX = ev.getX();
  48. mLastTouchDownY = ev.getY();
  49. //添加TouchTarget,则mFirstTouchTarget != null
  50. newTouchTarget = addTouchTarget(child, idBitsToAssign);
  51. //表示以及分发给NewTouchTarget
  52. alreadyDispatchedToNewTouchTarget = true;
  53. break;
  54. }

dispatchTransformedTouchEvent()方法实际就是调用子元素的dispatchTouchEvent()方法。

其中dispatchTransformedTouchEvent()方法的重要逻辑如下:

</>复制代码

  1. if (child == null) {
  2. handled = super.dispatchTouchEvent(event);
  3. } else {
  4. handled = child.dispatchTouchEvent(event);
  5. }

由于其中传递的child不为空,所以就会调用子元素的dispatchTouchEvent()。如果子元素的dispatchTouchEvent()方法返回true,那么mFirstTouchTarget就会被赋值,同时跳出for循环。

</>复制代码

  1. //添加TouchTarget,则mFirstTouchTarget != null
  2. newTouchTarget = addTouchTarget(child, idBitsToAssign);
  3. //表示以及分发给NewTouchTarget
  4. alreadyDispatchedToNewTouchTarget = true;

其中在addTouchTarget(child, idBitsToAssign);内部完成mFirstTouchTarget被赋值。如果mFirstTouchTarget为空,将会让ViewGroup默认拦截所有操作。如果遍历所有子View或ViewGroup,都没有消费事件。ViewGroup会自己处理事件。

3.3 得出结论

Android事件分发是先传递到ViewGroup,再由ViewGroup传递到View

在ViewGroup中通过onInterceptTouchEvent()对事件传递进行拦截

1.onInterceptTouchEvent方法返回true代表拦截事件,即不允许事件继续向子View传递;

2.返回false代表不拦截事件,即允许事件继续向子View传递;(默认返回false)

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

04.View事件的分发机制 4.1 源码分析

View中dispatchTouchEvent()的源码分析

</>复制代码

  1. public boolean dispatchTouchEvent(MotionEvent event) {
  2. if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
  3. mOnTouchListener.onTouch(this, event)) {
  4. return true;
  5. }
  6. return onTouchEvent(event);
  7. }

从上面可以看出:

只有以下三个条件都为真,dispatchTouchEvent()才返回true;否则执行onTouchEvent(event)方法

</>复制代码

  1. 第一个条件:mOnTouchListener != null
  2. 第二个条件:(mViewFlags & ENABLED_MASK) == ENABLED;
  3. 第三个条件:mOnTouchListener.onTouch(this, event);

下面,我们来看看下这三个判断条件:

第一个条件:mOnTouchListener!= null

</>复制代码

  1. //mOnTouchListener是在View类下setOnTouchListener方法里赋值的
  2. public void setOnTouchListener(OnTouchListener l) {
  3. //即只要我们给控件注册了Touch事件,mOnTouchListener就一定被赋值(不为空)
  4. mOnTouchListener = l;
  5. }

第二个条件:(mViewFlags & ENABLED_MASK) == ENABLED

该条件是判断当前点击的控件是否enable

由于很多View默认是enable的,因此该条件恒定为true

第三个条件:mOnTouchListener.onTouch(this, event)

回调控件注册Touch事件时的onTouch方法

</>复制代码

  1. //手动调用设置
  2. button.setOnTouchListener(new OnTouchListener() {
  3. @Override
  4. public boolean onTouch(View v, MotionEvent event) {
  5. return false;
  6. }
  7. });

如果在onTouch方法返回true,就会让上述三个条件全部成立,从而整个方法直接返回true。

如果在onTouch方法里返回false,就会去执行onTouchEvent(event)方法。

接下来,我们继续看:onTouchEvent(event)的源码分析

</>复制代码

  1. public boolean onTouchEvent(MotionEvent event) {
  2. final int viewFlags = mViewFlags;
  3. if ((viewFlags & ENABLED_MASK) == DISABLED) {
  4. // A disabled view that is clickable still consumes the touch
  5. // events, it just doesn"t respond to them.
  6. return (((viewFlags & CLICKABLE) == CLICKABLE ||
  7. (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
  8. }
  9. if (mTouchDelegate != null) {
  10. if (mTouchDelegate.onTouchEvent(event)) {
  11. return true;
  12. }
  13. }
  14. //如果该控件是可以点击的就会进入到下两行的switch判断中去;
  15. if (((viewFlags & CLICKABLE) == CLICKABLE ||
  16. (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
  17. //如果当前的事件是抬起手指,则会进入到MotionEvent.ACTION_UP这个case当中。
  18. switch (event.getAction()) {
  19. case MotionEvent.ACTION_UP:
  20. boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
  21. // 在经过种种判断之后,会执行到关注点1的performClick()方法。
  22. //请往下看关注点1
  23. if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
  24. // take focus if we don"t have it already and we should in
  25. // touch mode.
  26. boolean focusTaken = false;
  27. if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
  28. focusTaken = requestFocus();
  29. }
  30. if (!mHasPerformedLongPress) {
  31. // This is a tap, so remove the longpress check
  32. removeLongPressCallback();
  33. // Only perform take click actions if we were in the pressed state
  34. if (!focusTaken) {
  35. // Use a Runnable and post this rather than calling
  36. // performClick directly. This lets other visual state
  37. // of the view update before click actions start.
  38. if (mPerformClick == null) {
  39. mPerformClick = new PerformClick();
  40. }
  41. if (!post(mPerformClick)) {
  42. //关注点1
  43. //请往下看performClick()的源码分析
  44. performClick();
  45. }
  46. }
  47. }
  48. if (mUnsetPressedState == null) {
  49. mUnsetPressedState = new UnsetPressedState();
  50. }
  51. if (prepressed) {
  52. mPrivateFlags |= PRESSED;
  53. refreshDrawableState();
  54. postDelayed(mUnsetPressedState,
  55. ViewConfiguration.getPressedStateDuration());
  56. } else if (!post(mUnsetPressedState)) {
  57. // If the post failed, unpress right now
  58. mUnsetPressedState.run();
  59. }
  60. removeTapCallback();
  61. }
  62. break;
  63. case MotionEvent.ACTION_DOWN:
  64. if (mPendingCheckForTap == null) {
  65. mPendingCheckForTap = new CheckForTap();
  66. }
  67. mPrivateFlags |= PREPRESSED;
  68. mHasPerformedLongPress = false;
  69. postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
  70. break;
  71. case MotionEvent.ACTION_CANCEL:
  72. mPrivateFlags &= ~PRESSED;
  73. refreshDrawableState();
  74. removeTapCallback();
  75. break;
  76. case MotionEvent.ACTION_MOVE:
  77. final int x = (int) event.getX();
  78. final int y = (int) event.getY();
  79. // Be lenient about moving outside of buttons
  80. int slop = mTouchSlop;
  81. if ((x < 0 - slop) || (x >= getWidth() + slop) ||
  82. (y < 0 - slop) || (y >= getHeight() + slop)) {
  83. // Outside button
  84. removeTapCallback();
  85. if ((mPrivateFlags & PRESSED) != 0) {
  86. // Remove any future long press/tap checks
  87. removeLongPressCallback();
  88. // Need to switch from pressed to not pressed
  89. mPrivateFlags &= ~PRESSED;
  90. refreshDrawableState();
  91. }
  92. }
  93. break;
  94. }
  95. //如果该控件是可以点击的,就一定会返回true
  96. return true;
  97. }
  98. //如果该控件是不可以点击的,就一定会返回false
  99. return false;
  100. }

关注点1:

performClick()的源码分析

</>复制代码

  1. public boolean performClick() {
  2. sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
  3. if (mOnClickListener != null) {
  4. playSoundEffect(SoundEffectConstants.CLICK);
  5. mOnClickListener.onClick(this);
  6. return true;
  7. }
  8. return false;
  9. }

只要mOnClickListener不为null,就会去调用onClick方法;

那么,mOnClickListener又是在哪里赋值的呢?请继续看:

</>复制代码

  1. public void setOnClickListener(OnClickListener l) {
  2. if (!isClickable()) {
  3. setClickable(true);
  4. }
  5. mOnClickListener = l;
  6. }

当我们通过调用setOnClickListener方法来给控件注册一个点击事件时,就会给mOnClickListener赋值(不为空),即会回调onClick()。

4.2 得出结论

1.onTouch()的执行高于onClick()

2.每当控件被点击时:

如果在回调onTouch()里返回false,就会让dispatchTouchEvent方法返回false,那么就会执行onTouchEvent();如果回调了setOnClickListener()来给控件注册点击事件的话,最后会在performClick()方法里回调onClick()。

onTouch()返回false(该事件没被onTouch()消费掉) = 执行onTouchEvent() = 执行OnClick()

如果在回调onTouch()里返回true,就会让dispatchTouchEvent方法返回true,那么将不会执行onTouchEvent(),即onClick()也不会执行;

onTouch()返回true(该事件被onTouch()消费掉) = dispatchTouchEvent()返回true(不会再继续向下传递) = 不会执行onTouchEvent() = 不会执行OnClick()

4.3 验证结论

在回调onTouch()里返回true

</>复制代码

  1. TextView textView = findViewById(R.id.tv_13);
  2. //设置OnTouchListener()
  3. textView.setOnTouchListener(new View.OnTouchListener() {
  4. @Override
  5. public boolean onTouch(View v, MotionEvent event) {
  6. Log.d("小杨逗比","执行了onTouch(), 动作是:" + event.getAction());
  7. return true;
  8. }
  9. });
  10. //设置OnClickListener
  11. textView.setOnClickListener(new View.OnClickListener() {
  12. @Override
  13. public void onClick(View v) {
  14. Log.d("小杨逗比","执行了onClick()");
  15. }
  16. });

打印日志如下所示

注意action为0是ACTION_DOWN,为2是ACTION_MOVE,为1是ACTION_UP。

</>复制代码

  1. 2019-04-04 13:37:58.301 13616-13616/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:0
  2. 2019-04-04 13:37:58.315 13616-13616/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:2
  3. 2019-04-04 13:37:58.405 13616-13616/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:2
  4. 2019-04-04 13:37:58.408 13616-13616/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:1

在回调onTouch()里返回false

打印结果如下所示

</>复制代码

  1. 2019-04-04 13:41:26.961 14006-14006/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:0
  2. 2019-04-04 13:41:26.978 14006-14006/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:2
  3. 2019-04-04 13:41:27.072 14006-14006/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:2
  4. 2019-04-04 13:41:27.074 14006-14006/org.yczbj.ycrefreshview D/小杨逗比: 执行了onTouch(), 动作是:1
  5. 2019-04-04 13:41:27.076 14006-14006/org.yczbj.ycrefreshview D/小杨逗比: 执行了onClick()

总结:onTouch()返回true就认为该事件被onTouch()消费掉,因而不会再继续向下传递,即不会执行OnClick()。

05.思考一下 5.1 onTouch()和onTouchEvent()的区别

这两个方法都是在View的dispatchTouchEvent中调用,但onTouch优先于onTouchEvent执行。

如果在onTouch方法中返回true将事件消费掉,onTouchEvent()将不会再执行。

特别注意:请看下面代码

</>复制代码

  1. //&&为短路与,即如果前面条件为false,将不再往下执行
  2. //所以,onTouch能够得到执行需要两个前提条件:
  3. //1. mOnTouchListener的值不能为空
  4. //2. 当前点击的控件必须是enable的。
  5. mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
  6. mOnTouchListener.onTouch(this, event)

因此如果你有一个控件是非enable的,那么给它注册onTouch事件将永远得不到执行。对于这一类控件,如果我们想要监听它的touch事件,就必须通过在该控件中重写onTouchEvent方法来实现。

5.2 Touch事件的后续事件(MOVE、UP)层级传递

如果给控件注册了Touch事件,每次点击都会触发一系列action事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP等)

当dispatchTouchEvent在进行事件分发的时候,只有前一个事件(如ACTION_DOWN)返回true,才会收到后一个事件(ACTION_MOVE和ACTION_UP)

即如果在执行ACTION_DOWN时返回false,后面一系列的ACTION_MOVE和ACTION_UP事件都不会执行

从上面对事件分发机制分析知:

dispatchTouchEvent()和 onTouchEvent()消费事件、终结事件传递(返回true)

而onInterceptTouchEvent 并不能消费事件,它相当于是一个分叉口起到分流导流的作用,对后续的ACTION_MOVE和ACTION_UP事件接收起到非常大的作用

请记住:接收了ACTION_DOWN事件的函数不一定能收到后续事件(ACTION_MOVE、ACTION_UP)

这里给出ACTION_MOVE和ACTION_UP事件的传递结论

如果在某个对象(Activity、ViewGroup、View)的dispatchTouchEvent()消费事件(返回true),那么收到ACTION_DOWN的函数也能收到ACTION_MOVE和ACTION_UP

如果在某个对象(Activity、ViewGroup、View)的onTouchEvent()消费事件(返回true),那么ACTION_MOVE和ACTION_UP的事件从上往下传到这个View后就不再往下传递了,而直接传给自己的onTouchEvent()并结束本次事件传递过程。

其他介绍 01.关于博客汇总链接

1.技术博客汇总

2.开源项目汇总

3.生活博客汇总

4.喜马拉雅音频汇总

5.其他汇总

02.关于我的博客

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

简书:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜马拉雅听书:http://www.ximalaya.com/zhubo...

开源中国:https://my.oschina.net/zbj161...

泡在网上的日子:http://www.jcodecraeer.com/me...

邮箱:yangchong211@163.com

segmentfault头条:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

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

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

相关文章

  • View事件机制分析

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

    bergwhite 评论0 收藏0
  • Activity、Window、View三者关系

    摘要:在代码中的直接应用是或者是。就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与以及进行交互。创建需要通过创建,通过将加载其中,并将交给,进行视图绘制以及其他交互。创建机制分析实例的创建中执行,从而生成了的实例。 目录介绍 01.Window,View,子Window 02.什么是Activity 03.什么是Window 04.什么是DecorView 05.什么是Vi...

    Cristic 评论0 收藏0

发表评论

0条评论

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