和正常状态下的点击事件一样,Talkback下的点击事件也有相应的处理流程。
正常状态下的点击事件
正常状态下的点击事件主要有dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent(),
Talkback下的点击事件主要有
dispatchHoverEvent(),onInterceptHoverEvent(),onHoverEvent()
其中比较特殊的是onInterceptTouchEvent()和onInterceptHoverEvent()只有ViewGorup才有。
正常状态下的点击事件的分发流程如下:
以上都是针对事件ACTION_DOWN,ACTION_UP和ACTION_MOVE与之并不完全相同。简单的说,当dispatchTouchEvent()进行事件分发时,只有当ACTION_DOWN返回true时,才会接收到ACTION_MOVE和ACTION_UP事件。
Talkback下的点击事件的分发流程如下:
Tips:Android中经常遇到的是onTouchEvent()和onClick()事件的区别与使用,
正常情况下的触发过程是:onTouchEvent()[ACTION_DOWN] ->onTouchEvent()[ACTION_UP] -> onClick(),这是正常点击的事件触发过程,但是如果点下去之后有过滑动事件,那么触发的事件就会变成onTouchEvent()[ACTION_DOWN] ->onTouchEvent()[ACTION_MOVE] ->onTouchEvent()[ACTION_UP],并不会触发onClick()。
Talkback模式下,用户点击屏幕时,调用的是Activity.disPointerEvent()中的dispatchGenericMotionEvent()。最后调用View.dispatchGenericMotionEvent(),在该方法中如果判断事件为HoverEvent,就会调用ViewGroup.dispatchHoverEvent()开始进行事件分发,和onInterceptTouchEvent()方法类似,如果onInterceptHoverEvent()返回true,则表示这个ViewGroup会拦截这个事件,并自己处理;如果返回的是false,则表示不拦截这个事件,并将当前事件继续传递给子view,子view掉用自己的dispatchHoverEvent(),如此循环知道事件被处理。在事件处理阶段,view/viewgroup会先判断自己是否设置了OnHoverListener,并判断他的onHover()是否返回了true,如果返回了true,则不会调用onHoverEvent()。onHoverEvent()中会调用sendAccessibilityHoverEvent(),该方法和后续会调用以下方法:
sendAccessibilityEvent()、sendAccessibilityEventUnchecked()、onInitializeAccessbilityEvent()、dispatchPopulateAccessibilityEvent()、onPopulateAccessibilityEvent()、onRequestSendAccessibilityEvent()(仅在ViewGroup中默认实现)以上6中方法为当自定义View适配Talkback可以覆盖的方法,可以重写View的这些方法或者实现View.AccessibilityDelegate来解决一些特殊场景下Talkback播报的问题。
Talkback下使用的是双击代替正常状态的单击,在这种情况下,单击时触发的情况依次是onHoverEnter(),onHoverMove(),onHoverExit(),双击时则没有经历这样的过程,可以看到直接触发的onClick(),这里怀疑的是先触发performClick()从而触发onClick()。使用的是焦点的位置进行触发点击事件(即当选中一个按钮时,点击非按钮的位置同样会触发按钮的点击事件)。
Tips:和Talkback相关的控件属性还有两个,focusable和clickable。控件只设置focusable为true时,Talkback模式下无法选中;而只设置clickable为true时,Talk模式下可以选中,但是双击不会触发onClick()事件,只有当focusable和clickable都设置为true时,Talk模式下才能正常的选中并且双击触发相应的onClick()事件。