Android 可访问性:Talkback 以错误的顺序遍历元素 [英] Android accessibility: Talkback traverses elements in wrong order

查看:47
本文介绍了Android 可访问性:Talkback 以错误的顺序遍历元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有工具栏的布局和一个将托管其他控件的视图:

I have a layout with a toolbar and a view that will host other controls:

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ViewStub
        android:id="@+id/root_view_stub"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

使用 FrameLayout 以便具有正高度"的工具栏可以是半透明的,并且视图延伸到工具栏下方.工具栏和视图具有相同的顶部位置但不同的高度.当 Talkback 构建视图层次结构时,它会将工具栏放在底部,即使它是首先定义的.accessibilityTraversalBefore"和accessibilityTraversalAfter"对视图没有影响.到目前为止,我找到的唯一解决方案是向 ViewStub 添加 1px 或 0.1px 的顶部边距.这可能与这里的代码有关:

A FrameLayout is used so that the toolbar, which has a positive "elevation", can be translucent and the view extends to under the toolbar. The toolbar and the view have the same top position but different height. When Talkback builds the view hierarchy, it puts the toolbar at the bottom even though it's defined first. "accessibilityTraversalBefore" and "accessibilityTraversalAfter" on the views have no effect. The only solution I found so far was to add a top margin of 1px or 0.1px to the ViewStub. This probably has something to do with the code here:

https://github.com/google/talkback/blob/master/src/main/java/com/android/utils/traversal/ReorderedChildrenIterator.java

代码尝试根据节点的屏幕位置重新排序节点.添加顶部边距有点麻烦,可能有一天会中断.有没有更好的解决方案?

The code tries to reorder the nodes based on their screen positions. Adding the top margin is a bit hacky and may break some day. Is there a better solution?

推荐答案

在调试我的应用和 TalkBack 应用后,我弄清楚了发生了什么.可访问性遍历顺序不受布局中定义的视图顺序控制.在activity_react_native.xml 中向工具栏或ViewStub 添加accessibilityTraversalBefore 或accessibilityTraversalAfter 无效.我找不到任何关于遍历顺序的文档,所以我检查了代码.TalkBack 的工作原理如下:

I figured out what's going on after debugging my app and TalkBack app. The accessibility traversal order is not controlled by the order views are defined in the layout. Adding accessibilityTraversalBefore or accessibilityTraversalAfter to the toolbar or ViewStub in activity_react_native.xml has no effect. I couldn't find any documentation on traversal order so I checked out the code. Here is how TalkBack works:

打开 TalkBack 后,所有单指手势都会发送到 TalkBack 而不是应用.这些手势可以在 TalkBack 设置中重新定义.上下滑动手势后,TalkBack 首先枚举当前可见页面上的所有可聚焦视图.这是通过向应用程序发送消息来完成的.在应用进程中,无障碍视图层次结构是通过递归遍历所有子视图来构建的.它是在 ViewGroup 代码中完成的:://github.com/aosp-mirror/platform_frameworks_base/blob/d18ed49f9dba09b85782c83999a9103dec015bf2/core/java/android/view/ViewGroup.java#L8397.当两个视图具有相同的顶部、左侧和宽度时,高度较大的一个在高度或面积较小的之前,这在大多数情况下似乎是一个糟糕的选择.构建树后,将其发送回 TalkBack,然后 TalkBack 会根据 traversalBefore 或 traversalAfter 属性对元素重新排序.由于 Toolbar 和 ViewStub 不是可聚焦元素,因此它们不会出现在此树中,这就是这两个属性不起作用的原因.

When TalkBack is turned on, all one-finger gestures are sent to TalkBack instead of to the app. Those gestures can be redefined in TalkBack settings. After a swiping up and down gesture, TalkBack first enumerates all focusable views on the current visible page. This is done by sending a message to the app. In the app process, the accessibility view hierarchy is built by iterating through all child views recursively. It's done in ViewGroup code: https://github.com/aosp-mirror/platform_frameworks_base/blob/d18ed49f9dba09b85782c83999a9103dec015bf2/core/java/android/view/ViewGroup.java#L2314. The last argument of this call is a hardcoded true which sorts child views based on their positions on the screen. The comparison logic is here: https://github.com/aosp-mirror/platform_frameworks_base/blob/d18ed49f9dba09b85782c83999a9103dec015bf2/core/java/android/view/ViewGroup.java#L8397. When two views have the same top, left and width, the one with bigger height comes before the one with smaller height or area, which seems like a bad choice in most scenarios. After the tree is built, it's sent back to TalkBack, which then reorders the elements based on the traversalBefore or traversalAfter properties. Since the Toolbar and ViewStub aren't focusable elements, they don't appear in this tree, which is why those two properties don't work.

修复方法是将 android:importantForAccessibility 添加到工具栏和 ViewStub.这会将它们从 ViewGroup 添加到可访问性树中,以便 TalkBack 可以作用于 accessibilityTraversalBefore/After 属性.

The fix is to add android:importantForAccessibility to both toolbar and ViewStub. This will add them into the accessibility tree from the ViewGroup, so that TalkBack can act on accessibilityTraversalBefore/After attributes.

还有一种解决方法是将工具栏向上移动 1px,然后在里面添加 1px 填充.额外的 1px 应该被 FrameLayout 剪掉,所以没有视觉变化:

There is also an workaround that moves the toolbar upward by 1px then adds 1px padding inside. That extra 1px should be clipped by FrameLayout so there is no visual change:

android:layout_marginTop="-1px"
android:paddingTop="1px"

这篇关于Android 可访问性:Talkback 以错误的顺序遍历元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆