语义可见性

背景

当用户与屏幕的某个部分互动时,系统会执行点击测试,以确定将该互动路由到哪个视图。目前,hit regions 有两种类型:语义上可见和语义上不可见

HitTestInteraction 枚举用于指定语义(无障碍)点击测试是否应与它们互动。

从语义上讲,可见的命中区域既可与常规命中测试互动,也可与 accessibility hit testing 互动;而从语义上讲,不可见的命中区域只能与常规命中测试互动,例如通过鼠标或触摸事件进行互动。

智能显示屏案例研究

为了更好地了解为什么我们需要将语义可见性作为一种属性,不妨先看一个激励性示例。例如,考虑一下智能显示屏产品,它本质上是一个 Flutter 应用,有时可以启动子应用,例如 WebView。

父级 Flutter 应用可以启动包含 YouTube 播放器的子级 WebView。在这种情况下,有些命中应发送到 YouTube(例如播放或暂停视频),而另一些则应由父进程处理,例如完全关闭播放器的手势。由于这两种视图都是全屏视图,因此情况并非如此简单。

一种解决方案是让父 Flutter 进程放置一个全屏、透明且在语义上不可见的命中区域作为最顶层的视图。我们将此视图称为输入盾。借助输入屏蔽,Flutter 可以拦截所有输入,即使是针对 YouTube 播放器的输入,然后根据需要使用或重定向输入。

为了更好地了解为什么此输入屏障需要语义上不可见,我们不妨通过无障碍功能的探索模式来考虑一下如果不是这样会发生什么情况。在此模式下,用户在屏幕上拖动手指时,无障碍管理器会读出用户手指下方的任何内容。这些无障碍功能命中测试想要忽略输入屏障,而是读出其下方的“真实”内容。

通过使输入源在语义上不可见,可以实现这一目的。无障碍功能命中仅与语义上可见的命中区域互动,在本例中,该区域是 YouTube 播放器。

示例

简单情况

绿色(语义上不可见)视图叠加在蓝色(语义上可见)视图之上。语义命中测试不会看到绿色、语义上不可见的视图,因此会转到蓝色视图。

图表显示了常规命中测试如何以语义上不可见的视图为目标,而语义命中测试如何绕过该视图以语义上可见的底层视图为目标。

图片说明:语义上不可见的视图叠加在语义上可见的视图之上。常规命中测试会与所有视图互动,因此会命中语义上不可见的顶部视图。语义命中测试会忽略它,因此会命中底部在语义上可见的那个。

智能显示屏保护套

从上到下依次是透明视图、红色视图和蓝色视图。透明视图在语义上是不可见的,并且是全屏的;红色和蓝色视图表示用户可能想要互动的不同内容,例如由 Flutter 运行的网页或应用。 Flutter 内容不会直接接收常规命中,因为这些命中将由顶级视图处理,但 Flutter 内容会接收语义命中,例如由无障碍服务执行的语义命中,因为语义命中会忽略语义上不可见(以及视觉上不可见)的顶级视图。

智能显示屏示意图

图片说明:共有三个视图,从上到下依次表示不可见的语义屏障、YouTube 播放器和 Flutter 视图。常规点击测试会到达最顶层的视图,而不管语义可见性如何,因此透明的“输入屏蔽”会接收到这些测试。语义命中测试会忽略此最顶层的输入屏蔽层,因此会转到 Z-order 最高且在语义上可见的视图(即 YouTube 播放器)。