如何为RecyclerView中的卡片设置局部TalkBack无障碍遍历顺序?
实现RecyclerView单卡片内的无障碍遍历顺序
方案一:利用API 28+的accessibilityTraversalWithin属性(推荐)
如果应用最低支持Android 9(API 28),可直接通过布局属性实现局部遍历:
- 在
BumpCardView的根布局(MaterialCardView)中添加:
该属性会将当前卡片标记为独立的无障碍遍历容器,子View的遍历顺序仅在容器内部生效,不会影响全局。android:accessibilityTraversalWithin="true" - 在卡片内的文本控件
a11yText的布局中设置:
明确指定文本控件在图标控件之后被读取,由于android:accessibilityTraversalAfter="@id/a11y_icon"accessibilityTraversalWithin的限制,这个顺序只会作用于当前卡片内部,不会出现所有图标先读、再读所有文本的问题。
方案二:自定义AccessibilityDelegate兼容低版本
如果需要兼容API 28以下系统,通过自定义无障碍代理手动控制遍历顺序:
- 在
BumpCardView的初始化代码中,为卡片设置自定义AccessibilityDelegate:class BumpCardView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : MaterialCardView(context, attrs, defStyleAttr) { private lateinit var a11yIcon: ImageView private lateinit var a11yText: TextView init { inflate(context, R.layout.layout_bump_card, this) a11yIcon = findViewById(R.id.a11y_icon) a11yText = findViewById(R.id.a11y_text) setAccessibilityDelegate(object : View.AccessibilityDelegate() { override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo?) { super.onInitializeAccessibilityNodeInfo(host, info) info ?: return // 清除默认的全局遍历关联 info.removeAllAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY) info.removeAllAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY) // 手动添加当前卡片内的子节点,并指定顺序:先图标,后文本 val iconNode = a11yIcon.createAccessibilityNodeInfo() val textNode = a11yText.createAccessibilityNodeInfo() info.addChild(iconNode) info.addChild(textNode) // 确保当前卡片遍历完成后,才切换到下一个卡片 parent?.let { info.setTraversalAfter(it, this@BumpCardView) } } }) } } - Java版本逻辑一致,只需调整语法适配即可。
注意事项
- 避免使用全局的
accessibilityTraversalAfter/accessibilityTraversalBefore属性,这类属性基于视图ID全局生效,在RecyclerView复用item时必然出现顺序混乱。 - 测试时务必开启TalkBack,实际滑动验证遍历顺序是否符合预期,无障碍特性的表现可能因系统版本或TalkBack版本略有差异。
内容的提问来源于stack exchange,提问作者Sazbak
相关产品推荐
相关产品推荐

