在如今这个注重用户体验的时代,无障碍模式对于特殊需求的用户来说意义非凡。然而,其背后的技术流程却很少被大众所熟知,这是值得我们深入探讨的。
无障碍模式下的事件转换
无障碍模式下的事件转换是整个流程中的关键部分。要知道,不同类型的事件在无障碍模式运行环境中有着不一样的角色。在实际应用里,就像在某些特定的设备上,当用户触发某个触摸动作时,该动作对应的原始事件会按照既定的规则进行转换。例如,可能将普通的触摸坐标事件转换为无障碍事件的一种特定格式。而且,这种转换也需要考虑设备性能的影响。如果设备性能较差,转换过程可能会出现卡顿。
这一转换,是确保后续流程能够顺利进行的前置条件。转换过程中,任何一个小的环节出错,都可能导致后续的辅助app无法准确处理事件。像有的时候,开发过程中代码的一个小的逻辑错误,就可能致使转换后的事件错误,进而影响整个无障碍操作流程。
触摸事件到Activity的传递过程
触摸事件到Activity之间的传递可不是简单的转手。从用户手指触摸屏幕那个瞬间开始,系统就开始一系列复杂的操作。比如说在一个典型的安卓手机中,触摸传感器检测到触摸后,会将电信号传递给内核,内核再将这个信息通过框架层传递给Activity。这个过程涉及到很多不同的系统组件,它们需要协同工作。
bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
if (source & AINPUT_SOURCE_CLASS_POINTER) {
// Specifically excludes HOVER_MOVE and SCROLL.
switch (action & AMOTION_EVENT_ACTION_MASK) {
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_CANCEL:
case AMOTION_EVENT_ACTION_OUTSIDE:
return true;
}
}
return false;
}
在这一传递中,时序也是非常重要的。因为如果时序出现偏差,就可能导致触摸事件在Activity中的状态与实际不符。例如在某个游戏app中,触摸操作需要及时反馈到Activity,如果传递过慢,就可能影响玩家的实际体验,导致操作无法及时生效。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
}
事件传递给具体的View的分发过程
@Override
public boolean dispatchGenericMotionEvent(MotionEvent ev) {
final Window.Callback cb = mWindow.getCallback();
return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
? cb.dispatchGenericMotionEvent(ev) : super.dispatchGenericMotionEvent(ev);
}
当事件来到了要传递给具体的View的分发流程时,情况变得更为复杂。系统要在众多可能的View中确定哪个View才是真正的目标对象。以某购物app为例,页面上可能有多个按钮和图标,当用户点击时,系统需要精确地把事件分发给被点击的那个View。
分发过程还会受到View层级结构的影响。如果View的层级结构混乱或者嵌套过多,就可能导致分发出现错误。假设有一个多层嵌套布局的新闻阅读app,当用户想要点击文章中的某个评论图标时,可能因为错误的分发而使点击操作无法正确响应,影响用户进行互动。
最终无障碍事件的执行流程
终于到了最终的无障碍事件执行流程了。这个流程是经过前面多个步骤铺垫得来的。当无障碍事件通过前面一系列过程到达最终环节时,就像火车到达终点站。在执行过程中,首先要确保相关的组件已经完成初始化并且处于可用状态。例如TalkBack,如果没有正确初始化朗读引擎,那么就无法正常朗读View的内容。
同时,这个执行流程还依赖于之前事件传递过程中携带的信息的准确性。就像一个快递包裹,如果地址被写错了,也无法准确送到目的地。假设事件传递中关于View内容的标识出现错误,那朗读出来的内容就可能是错误的,这对依赖无障碍功能的用户来说是很糟心的事。
自定义View的适配方法
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
当开发人员进行自定义View时,怎样适配无障碍模式就是一个很实际的问题。有6种方法是可以覆盖实现的。这些方法的实现能够解决特殊场景下TalkBack播报的问题。例如在一些有着特殊交互设计的app中,为了让TalkBack能够准确播报,开发人员就需要合理利用这些方法。像有个音乐制作app,它的界面设计独特,为了确保盲人用户也能正常使用,就必须利用好这些适配方法,不然盲人用户在操作中就无法从TalkBack获得正确的操作引导。
public boolean dispatchGenericMotionEvent(MotionEvent event) {
···
final int source = event.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
final int action = event.getAction();
//判断事件类型属于Hover,调用dispatch方法开始进行分发
if (action == MotionEvent.ACTION_HOVER_ENTER
|| action == MotionEvent.ACTION_HOVER_MOVE
|| action == MotionEvent.ACTION_HOVER_EXIT) {
if (dispatchHoverEvent(event)) {
return true;
}
}
...
return false;
}
整体流程的协同合作
整个从被辅助app到辅助app的无障碍事件传递和处理流程是一个协同合作的典范。从最初的事件转换到最后的执行,每个环节都不可或缺。就像一个庞大的工厂流水线,任何一个工人停止工作都会影响产品的最终质量。在一款社交app中,如果其中一个环节出现问题,比如事件分发错误,那盲人用户在浏览朋友圈或者聊天时就会遇到障碍,无法顺利获取信息或者进行回复操作。
大家知道在开发过程中,如何才能更好地监测和优化这个整体流程中的每个环节吗?希望大家能积极评论分享自己的看法,也欢迎点赞分享这篇文章。