假设你有一个LinearLayout
在一个RelativeLayout
中,它包含3个TextViews
和artist, song and album
:
<RelativeLayout
...
<LinearLayout
android:id="@id/text_view_container"
android:layout_width="warp_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@id/artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Artist"/>
<TextView
android:id="@id/song"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Song"/>
<TextView
android:id="@id/album"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="album"/>
</LinearLayout>
<TextView
android:id="@id/unrelated_textview1/>
<TextView
android:id="@id/unrelated_textview2/>
...
</RelativeLayout>
当您激活TalkbackReader并点击LinearLayout
中的TextView
时,TalkbackReader将读取例如“艺术家”,“歌曲”或“专辑”。
但是你可以把前3个TextViews
放入一个焦点小组,方法是:
<LinearLayout
android:focusable="true
...
现在TalkbackReader会读到“艺术家歌曲专辑”。
**2 unrelated TextViews
仍然是独立的,不读取,这是我想要实现的行为。
(See Google codelabs示例供参考)
我现在试图用ConstrainLayout
重新创建这种行为,但看不出如何。
<ConstraintLayout>
<TextView artist/>
<TextView song/>
<TextView album/>
<TextView unrelated_textview1/>
<TextView unrelated_textview2/>
</ConstraintLayout>
将小部件放入“组”似乎不起作用:
<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:importantForAccessibility="yes"
app:constraint_referenced_ids="artist,song,album"
/>
那么,我如何在ConstrainLayout
中重新创建可访问性焦点组?
**[编辑]:**似乎是这样的,创建解决方案的唯一方法是在外部ConstraintLayout上使用“focusable=true”和/或在视图本身上使用“focusable=false”。这有一些缺点,在处理键盘导航/切换框时应该考虑:
https://github.com/googlecodelabs/android-accessibility/issues/4
7条答案
按热度按时间icnyk63a1#
基于
ViewGroups
的焦点组仍然可以在ConstraintLayout
中工作,所以你可以用ConstraintLayouts
替换LinearLayouts
和RelativeLayouts
,TalkBack仍然可以按预期工作。但是,如果你试图避免在ConstraintLayout
中 * 嵌套 *ViewGroups
,保持平面视图层次结构的设计目标,这里有一种方法可以做到这一点。将
TextViews
从您提到的焦点ViewGroup
直接移动到顶级ConstraintLayout
。现在我们将使用ConstraintLayout
约束在这些TextViews
之上放置一个简单的透明View
。每个TextView
将成为顶级ConstraintLayout
的成员,因此布局将是平坦的。由于覆盖层位于TextViews
的顶部,因此它将在底层TextViews
之前接收所有触摸事件。以下是布局结构:我们现在可以手动为覆盖层指定一个内容描述,它是每个底层
TextViews
的文本的组合。为了防止每个TextView
接受焦点并说出自己的文本,我们将设置android:importantForAccessibility="no"
。当我们触摸覆盖视图时,我们听到TextViews
的组合文本。以上是一般的解决方案,但更好的是,将是一个自定义覆盖视图的实现,将自动管理事情。下面显示的自定义覆盖遵循
ConstraintLayout
中Group
助手的一般语法,并自动化上面概述的大部分处理。自定义覆盖执行以下操作:
1.接受一个id列表,这些id将按控件分组,如
ConstraintLayout
的Group
助手。1.通过在每个视图上设置
View.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO)
来禁用分组控件的可访问性。(这避免了手动执行此操作。)1.单击自定义控件时,它会将分组视图的文本串联到辅助功能框架。为视图收集的文本来自
contentDescription
、getText()
或hint
。(这避免了手动执行此操作。另一个优点是,它还将在应用运行时拾取对文本所做的任何更改。)TextViews
。*下面是一个示例布局,显示了问题中提到的
ViewGroup
方法和自定义覆盖。右边是使用自定义控件的覆盖方法。顶部标记为“初始焦点”的TextView
只是为了捕获初始焦点,以便于比较两种方法。选择
ConstraintLayout
后,TalkBack会显示“艺术家、歌曲、专辑”。选择自定义视图覆盖后,TalkBack还会显示“艺术家、歌曲、专辑”。
下面是自定义视图的示例布局和代码。* 注意:虽然这个自定义视图使用
TextViews
可以达到指定的目的,但它并不是传统方法的可靠替代品。例如:自定义覆盖将说出扩展TextView
(如EditText
)的视图类型的文本,而传统方法则不会。在GitHub上查看sample project。
活动_主要.xml
AccessibilityOverlay.java
属性.xml
定义自定义覆盖视图的自定义属性。
u59ebvdq2#
我最近遇到了同样的问题,我决定使用新的ConstraintLayout帮助器(自constraintlayout 1.1起可用)实现一个新的Class,以便我们可以以使用Group视图的相同方式使用它。
该实现是Cheticamp's answer的简化版本,他的想法是创建一个新的视图来处理可访问性。
下面是我的实现:
也可作为要点:https://gist.github.com/JulienArzul/8068d43af3523d75b72e9d1edbfb4298
您可以像使用组一样使用它:
此示例将TextView和ImageView组织在一个组中,以实现辅助功能。您仍然可以添加其他视图,这些视图将获得焦点并由ConstraintLayout中的辅助功能读取器读取。
视图是透明的,但您可以使用常规约束布局属性选择聚焦时显示视图的区域。
在我的示例中,辅助功能组显示在整个ConstraintLayout上,但您可以通过修改
app:"layout_constraint..."
属性来选择将其与某些或所有引用的视图对齐。编辑:根据@Mel'在评论中的建议,我更新了
ConstraintLayoutAccessibilityHelper
类,以确保在Accessibility事件中只添加可见的视图。hrysbysz3#
设置内容描述
确保
ConstraintLayout
被设置为可聚焦,并带有显式的内容描述。此外,确保子TextViews
不设置为可聚焦,除非您希望它们被独立读取。可扩展标记语言
** java **
如果您希望在代码中动态设置ConstraintLayout的内容描述,则可以将每个相关
TextView
的文本值连接起来:辅助功能结果
启用Talkback后,ConstraintLayout现在将获得焦点并读出其内容描述。
屏幕截图,Talkback显示为标题:
详解
下面是上面示例截图的完整XML。注意,focusable和content description属性只在父级ConstraintLayout中设置,而不是在子级TextView中设置。这使得TalkBack永远不会关注单个子视图,而只关注父级容器(因此,只阅读父级容器的内容描述)。
嵌套焦点项
如果您希望不相关的TextViews能够独立于父级ConstraintLayout进行聚焦,则可以将这些TextViews也设置为
focusable=true
。这将导致这些TextViews变得可聚焦并单独读取,* 在 * ConstraintLayout之后。如果要将不相关的TextViews分组到单个TalkBack公告中(与ConstraintLayout分开),则选项有限:
1.将不相关的视图嵌套到另一个
ViewGroup
中,并使用它自己的内容描述,或者1.只在第一个不相关的项目上设置
focusable=true
,并将其内容描述设置为该子组的单个公告(例如“不相关的项目”)。选项#2会被认为是一种技巧,但它允许您维护一个平面视图层次结构(如果您真的想避免嵌套)。
但是如果你要实现焦点项的多个子分组,更合适的方法是将分组组织为嵌套的ViewGroups。根据Android关于自然分组的可访问性文档:
要为一组相关内容定义适当的聚焦模式,请将结构的每一部分放入其自己的可聚焦ViewGroup中
wko9yo5t4#
Android引入了
android:screenReaderFocusable
来对约束布局中的内容进行分组。这将适用于上述情况。但需要API级别27。https://developer.android.com/guide/topics/ui/accessibility/principles#content-groups
juud5qan5#
1.将约束布局设置为focusable(通过在约束布局中设置android:focusable=“true”)
1.将内容描述设置为约束布局
基于注解编辑仅适用于约束布局中存在单个焦点组的情况。
x33g5p2x6#
仅在XML中。
对于我的特殊情况,我默认情况下将视图分组在可访问性中,并将“important for accessibility field”设置为yes。
android: importantForAccessibility="yes"
这没有任何作用,但当我转到EACH视图并分别设置importantForAccessibility时
android: importantForAccessibility="yes"
如果你想宣布android: importantForAccessibility="no"
,如果你不想让它被公布--这解决了我的问题。2fjabf4q7#
我已经做了Julien Arzul的答案的一个版本,它不需要你手动为不可见的View设置约束。这个类扩展了ConstraintLayout的Layer类,它会自动适应显示在引用的View id上。
有一个问题,我最近一直在面对它,虽然(这也发生在朱利安的版本),如果你有一个解决方案,请让我知道。
Since version 13 Talkback has a feature that recognizes text/icons/images without content descriptions and does OCR on them说出它在视图中识别的内容,因此使用此解决方案,Talkback首先像我们想要的那样读取我们不可见的视图的描述,但之后它还读取我们试图通过importantForAccessibility=“no”隐藏的视图的内容。
所以它最后会说:“textViewOneText,textViewTwoText;检测到:text textViewOneText**textViewTwoText"。