欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

揭开事件分发机制的神秘面纱:第一部分解析

最编程 2024-01-18 21:07:57
...

前言

本文粗略解析下事件分发机制,后续会分析下源码,希望能够帮助到大家解惑一二。

从一个例子说起

在实践中,大多数需要了解事件分发机制的可能就是滑动冲突了,需要了解什么时候到底谁应该处理这个事件,先来看个例子,当我们点击区域View

默认不处理事件

假如ViewGroup和View都默认不处理事件,不复写对应函数

  • DOWN事件传递到View的onTouchEvent,返回false,表示View本身不关心这次事件
  • DOWN事件传递到ViewGroup的onTouchEvent,返回false,表示ViewGroup本身不关心这次事件
  • 最终事件回溯到Activity中,由最上层处理事件

由于onTouchEvent中返回了false,同时也就代表着不关心本次事件(我不关心这次手势,不要来找我了),后续的MOVE,UP事件也不会传递进来

View处理事件

假设View是需要处理事件,比如是Button之类的View,默认是可点击的

  • DOWN事件传递到View的onTouchEvent,返回True,处理自己的逻辑
  • 因为View中的onTouchEvent返回了True,表示有人愿意处理了这个事件,那么后续事件将不会传递到ViewGroup以及上层的onTouchEvent中了,后续的事件将由View本身进行处理

注意上述的前提是ViewGroup不会对此事件进行拦截,因为在DOWN事件传递到View的ontouchEvent之前,ViewGroup是有一次拦截机会的,如果ViewGroup的onInterceptTouchEvent返回false,则不拦截,但是注意下一次的MOVE、UP等事件还是会走ViewGroup拦截的判断,可根据逻辑进行拦截处理,如果没有拦截,但是View的ontouchEvent返回了false,也就表示下面没有View是愿意处理这个事件的,那么这个烫手的山芋(事件)还是会回到ViewGroup的ontouchEvent中

同时可见DOWN事件的返回值,其实就是表示着View本身对本次事件处理的意愿如何,True则代表着愿意处理该事件,false则代表不关心本次事件

ViewGroup拦截事件

假如ViewGroup在DOWN事件中,拦截了事件onInterceptTouchEvent返回了true,那么此时事件直接转到ViewGroup的ontouchEvent中,后续的MOVE、UP事件也会交给ViewGroup处理,View是没有机会处理到事件的,即使此时调用requestDisallowInterceptTouchEvent也是无效的

假如ViewGroup在DOWN事件中没有拦截事件,但是在MOVE中却对事件进行了拦截处理,比如类似如ScrollView一样,是可以对其中的View进行点击处理的,但是在滑动时,ScrollView需要处理自己的逻辑,这时候就在MOVE中拦截了事件

  • DOWN事件传递在ViewGroup中,但此时并不想拦截,onInterceptTouchEvent返回false,事件传递到View的ontouchEvent中,消费掉返回True
  • MOVE事件传递到ViewGroup中,此时ViewGroup需要对事件进行拦截处理,onInterceptTouchEvent返回True,但是View还苦巴巴的等着事件呢,因为之前在ontouchEvent中返回了True,那么此时这个MOVE事件将会被系统变成一个CANCEL事件,这个CANCEL事件将会传递给VIEW的onTouchEvent方法,告诉你,别等了,你的事件被取消了
  • 当MOVE事件或者UP事件再次进入ViewGroup的时候,注意此时由于之前已经拦截了事件,此次事件并不会走onInterceptTouchEvent的判断,可以理解为onInterceptTouchEvent一旦返回了True,那么后续的一系列事件就默认已经被拦截处理了,不会再去判断!而是会直接传递给ViewGroup的onTouchEvent方法去处理了
  • 此时View就不会受到任何的事件了

总结

  • 同一时间序列事件是指以down事件开始,中间含有数量不定的move事件,最终以up事件结束。

  • 各个View的onTouchEvent方法对DOWN事件的处理,代表了该View对以此DOWN开始的整个手势事件的处理意愿,True代表需要处理此次事件,false则表示不关心,事件会回传到上层View的ontouchEvent中

  • 如果ViewGroup一旦决定拦截一个事件,也就是onInterceptTouchEvent返回True,那么后续的同一时间序列事件将会被默认拦截,不会再调用onInterceptTouchEvent方法,后续事件会交给ontouchEvent进行处理

  • 事件一旦交给一个View处理,那么它就必须消耗掉,否则同一事件序列中剩下的事件就不再交给他来处理了,如果ontouchEvent中返回false,那么后续事件不会再传递进来

  • 如果ViewGroup拦截了一个半路的事件(比如,MOVE),这个事件将会被系统变成一个CANCEL事件,并传递给之前处理该手势(gesture)的子View,而且不会再传递(无论是被拦截的MOVE还是系统生成的CANCEL)给ViewGroup的onTouchEvent方法。只有再到来的事件才会传递到ViewGroup的onTouchEvent方法中。

请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!