无障碍 Kotlin:编写不抛弃用户的代码

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

为什么 Kotlin 中的无障碍是超能力,而非打勾项

\n\n

想象一下:你用 Kotlin 写了一个很酷的应用。漂亮的 Material Design、流畅的动画、响应式数据流。你为代码感到自豪。但后来发现,一位视力障碍的用户无法点击“购买”按钮,因为 TalkBack 将其读作“未标记按钮”。或者一位手部震颤的用户总是点不到那个微小的开关。

\n\n

无障碍并非枯燥的官僚流程。它关乎让你的 Kotlin 代码为每个人服务。根据世界卫生组织的数据,超过十亿人患有某种残疾。忽视他们,就意味着失去用户群体,而且坦率地说,也不是一名优秀的开发者。

\n\n

在本文中,我们将探讨如何毫无痛苦地编写无障碍的 Kotlin 代码。无需大量样板代码。提供可直接复制粘贴的生动示例。

\n\n

基本原则:ContentDescription——你最好的朋友

\n\n

无障碍中最常见的失败点就是缺少界面元素的描述。Android 上的屏幕阅读器 TalkBack 无法读取图片或图标。它需要文字。

\n\n

在 Kotlin 中,这通过 contentDescription 属性实现。但不要简单写成“按钮”,而要描述其含义。

\n\n

糟糕的示例(请勿这样做)

\n
imageView.contentDescription = "按钮"
\n\n

良好的示例

\n
binding.fabAddTask.contentDescription = "添加新任务"
\n\n

如果图标是装饰性的(仅用于美化),请设置 contentDescription = null,以便 TalkBack 忽略它。

\n\n
// 装饰性图标——不打扰用户\nbinding.decorativeIcon.contentDescription = null
\n\n

提示: 使用字符串资源(strings.xml)以支持本地化。不要在 Kotlin 文件中硬编码中文文本。

\n\n

语义标记:告诉系统什么重要

\n\n

标准的 View(如 Button、TextView)表现尚可,但自定义组件常常破坏无障碍。在 Kotlin 中,我们可以显式地设置语义。

\n\n

为元素添加角色

\n
binding.customView.importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES\nbinding.customView.accessibilityDelegate = object : View.AccessibilityDelegate() {\n    override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {\n        super.onInitializeAccessibilityNodeInfo(host, info)\n        info.text = "当前值:${viewModel.value}"\n        info.contentDescription = "音量滑块"\n    }\n}
\n\n

这段代码告诉系统:“嘿,这不只是一个方块,这是一个滑块!”。TalkBack 会明白该元素是可交互的,并能正确地进行交互。

\n\n

元素分组

\n

如果你的商品卡片包含图片、价格和名称,请将它们合并为一个焦点。否则,用户将逐个听取三个独立元素。

\n\n
binding.cardProduct.apply {\n    isFocusable = true\n    contentDescription = "商品:${product.name},价格:${product.price} 元"\n}
\n\n

现在,TalkBack 只需一次点击即可读取所有信息。

\n\n

操作导航:键盘与方向键

\n\n

并非所有用户都通过触摸屏幕操作。有些人使用键盘(通过 OTG)或方向键(遥控器)。你的应用应支持无需触摸即可操作。

\n\n

在 Kotlin 中,这通过 focusable 和焦点顺序(nextFocusDown、nextFocusForward)来解决。

\n\n
binding.buttonNext.nextFocusForwardId = R.id.buttonConfirm\nbinding.buttonConfirm.nextFocusDownId = R.id.buttonCancel
\n\n

请确保所有可交互元素都能获得焦点。一个常见错误是带有 ClickableSpan(文本中的链接)的 TextView。默认情况下,它无法获得焦点。修复方法如下:

\n\n
binding.textWithLink.movementMethod = LinkMovement                

博客

书籍推荐