最佳实践 | 助您提升应用的无障碍功能

最佳实践 | 助您提升应用的无障碍功能

某些使用 Android 设备的用户具有不同于他人的无障碍功能需求。为了帮助具有共同的无障碍功能需求的特定人群,Android 框架为开发者创建无障碍服务提供了相关功能,这种服务可将应用的内容呈现给此类用户,并代表他们在应用中执行操作。

Android 提供了一些系统无障碍服务,其中包括:

  • TalkBack: 帮助视力低下或失明的人。通过合成语音读出内容,并在应用中执行操作以响应用户手势。
  • 开关控制: 帮助有运动障碍的人。突出显示互动元素,并执行操作以响应用户按某个按钮的动作。用户只使用 1 个或 2 个按钮就能控制设备。

TalkBack

https://support.google.com/accessibility/android/answer/6283677

开关控制

https://support.google.com/accessibility/android/answer/6122836

为了帮助具有无障碍功能需求的用户顺利使用您的应用,应用应遵循本页中介绍的最佳做法,这些做法基于中所述的关键准则。

以下各种最佳做法可以进一步改进应用的无障碍功能:

  • 标签元素: 用户应该能够理解应用中每个有意义的互动界面元素的内容和用途。
  • 使用或扩展系统微件: 基于框架包含的视图元素构建,而不是创建您自己的自定义视图。框架的视图和微件类已经提供了应用所需的大多数无障碍功能。
  • 使用除颜色之外的提示: 用户应该能够明确区分界面中的各类元素。为此,除了颜色之外,还应使用图案和位置表示这些差异。
  • 让媒体内容使用起来更没有障碍: 尝试向应用的视频或音频内容添加说明,这样使用这些内容的用户就无需完全依靠视觉或听觉提示。

标签元素

请务必针对应用中的每个互动界面元素,为用户提供实用且描述性的标签。每个标签都应说明特定元素的含义和用途。TalkBack 等屏幕阅读器可以向依靠这些服务的用户读出这些标签。

在大多数情况下,您可以在包含给定界面元素的布局资源文件中指定该元素的说明。虽然您通常使用 contentDescription 属性添加标签,如指南中所述,但还需要牢记一些其他标签添加方法,如下面几部分所述。

可修改的元素

为可修改的元素 (如 EditText 对象) 添加标签时,您可以列举有效输入的示例,除了让相应的示例文字可由屏幕阅读器读出之外,最好还在元素本身中显示这些文字。在这些情况下,您可以使用 android:hint 属性,如以下代码段所示:

<!-- The hint text for en-US locale would be
     "Apartment, suite, or building". -->
<EditText
   android:id="@+id/addressLine2"
   android:hint="@string/aptSuiteBuilding" ... />

在这种情况下,View 对象的 android:labelFor 属性应设为 EditText 元素的 ID。如需了解详情,请参阅下文中介绍如何为相互描述的元素对添加标签的部分。

EditText

https://developer.android.google.cn/reference/android/widget/EditText

相互描述的元素对

给定的 EditText 元素通常会有一个相应的 View 对象,该对象描述了用户应在 EditText 元素中输入的内容。在搭载 Android 4.2 (API 级别 17) 或更高版本的设备上,您可以通过设置 View 对象的 android:labelFor 属性来指明这种关系。

View

https://developer.android.google.cn/reference/android/view/View

下面的代码段显示了为此类元素对添加标签的示例:

<!-- Label text for en-US locale would be "Username:" -->
<TextView
   android:id="@+id/usernameLabel" ...
   android:text="@string/username"
   android:labelFor="@+id/usernameEntry" />


<EditText
   android:id="@+id/usernameEntry" ... />


<!-- Label text for en-US locale would be "Password:" -->
<TextView
   android:id="@+id/passwordLabel" ...
   android:text="@string/password
   android:labelFor="@+id/passwordEntry" />


<EditText
   android:id="@+id/passwordEntry"
   android:inputType="textPassword" ... />

集合中的元素

向集合中的元素添加标签时,每个标签都应该是唯一的。这样,系统的无障碍服务在读出标签时就可以特指屏幕上的 1 个元素。这种对应关系可让用户知道他们何时循环浏览界面,或何时将焦点移到了已经发现的元素。

需要特别注意的是,您应在重用布局内的元素 (如 RecyclerView 对象) 中添加更多文字或上下文信息,以便能够唯一标识每个子元素。

RecyclerView

https://developer.android.google.cn/reference/androidx/recyclerview/widget/RecyclerView

为此,请在适配器实现中设置内容说明,如以下代码段所示

data class MovieRating(val title: String, val starRating: Integer)


class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
        RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {


    class MyRatingViewHolder(val ratingView: ImageView) :
            RecyclerView.ViewHolder(ratingView)


    override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
        val ratingData = myData[position]
        holder.ratingView.contentDescription = "Movie ${position}: " +
                "${ratingData.title}, ${ratingData.starRating} stars"
    }
}

相关内容组

如果应用显示的多个界面元素构成一个自然组 (如歌曲的详细信息或消息的属性),应将这些元素整理到一个容器中,该容器通常是 ViewGroup 的子类。将容器对象的 android:screenReaderFocusable 属性设为 true,并将每个内部对象的 android:focusable 属性设为 false。这样,无障碍服务就可以在单次语音中逐个读出内部元素的内容说明。这样整合相关元素有助于使用辅助技术的用户更高效地发现屏幕上的信息。

android:screenReaderFocusable

https://developer.android.google.cn/reference/android/view/View#attr_android:screenReaderFocusable

android:focusable

https://developer.android.google.cn/reference/android/view/View#attr_android:focusable

注意: 在 Android 8.1 (API 级别 27) 及更低版本中,android:screenReaderFocusable 属性不可用,因此应改为设置容器的 android:focusable 属性

以下代码段包含彼此相关的内容片段,因此容器元素 (即 ConstraintLayout 的实例) 的 android:screenReaderFocusable 属性设为 true,每个内部 TextView 元素的 android:focusable 属性设为 false:

<!-- In response to a single user interaction, accessibility services announce
     both the title and the artist of the song. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true">


    <TextView
        android:id="@+id/song_title" ...
        android:focusable="false"
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"
        android:focusable="false"
        android:text="@string/my_songwriter" />
</ConstraintLayout>

由于无障碍服务在单次语音中读出内部元素的说明,因此务必确保每条说明都简明扼要地传达出元素的含义。

自定义组标签

如果需要,您可以通过为某个组本身提供内容说明,替换平台中该组的内部元素说明的默认分组和排序。

以下代码段展示了一个示例自定义组说明:

<!-- In response to a single user interaction, accessibility services
     announce the custom content description for the group. -->
<ConstraintLayout
    android:id="@+id/song_data_container" ...
    android:screenReaderFocusable="true"
    android:contentDescription="@string/title_artist_best_song">


    <TextView
        android:id="@+id/song_title" ...


        <!-- Content ignored by accessibility services -->
        android:text="@string/my_song_title" />
    <TextView
        android:id="@+id/song_artist"


        <!-- Content ignored by accessibility services -->
        android:text="@string/my_songwriter" />
</ConstraintLayout>

嵌套组

如果应用的界面显示多维信息 (如节日活动的每日列表),应对内部组容器使用 android:screenReaderFocusable 属性。这种标签添加方案可以很好地平衡发现屏幕内容所需的语音条数与每条语音的长度。

以下代码段展示了一种为较大的组内的组添加标签的方法:

<!-- In response to a single user interaction, accessibility services
     announce the events for a single stage only. -->
<ConstraintLayout
    android:id="@+id/festival_event_table" ... >
    <ConstraintLayout
        android:id="@+id/stage_a_event_column"
        android:screenReaderFocusable="true">


        <!-- UI elements that describe the events on Stage A. -->


    </ConstraintLayout>
    <ConstraintLayout
        android:id="@+id/stage_b_event_column"
        android:screenReaderFocusable="true">


        <!-- UI elements that describe the events on Stage B. -->


    </ConstraintLayout>
</ConstraintLayout>

文字中的标题

某些应用使用标题总结屏幕上显示的多组文字。如果特定的 View 元素表示一个标题,您可以通过将该元素的 android:accessibilityHeading 属性设为 true,表明它的无障碍服务用途。

android:accessibilityHeading

https://developer.android.google.cn/reference/android/view/View#attr_android:accessibilityHeading

无障碍服务的用户可以选择浏览标题,而不是浏览段落或字词。这种灵活性可改善文字浏览体验。

无障碍窗格标题

在 Android 9 (API 级别 28) 及更高版本中,您可以为屏幕的窗格提供使用起来没有障碍的标题。出于无障碍目的,窗格是窗口中能够从视觉上加以区分的部分,如 Fragment 的内容。为了让无障碍服务能够理解与窗口行为类似的窗格行为,您应该为应用的窗格指定描述性标题。这样一来,当窗格的外观或内容发生变化时,无障碍服务就可以为用户提供更精细的信息。

如需指定窗格的标题,请使用 android:accessibilityPaneTitle 属性,如以下代码段所示:

<!-- Accessibility services receive announcements about content changes
     that are scoped to either the "shopping cart view" section (top) or
     "browse items" section (bottom) -->
<MyShoppingCartView
     android:id="@+id/shoppingCartContainer"
     android:accessibilityPaneTitle="@string/shoppingCart" ... />


<MyShoppingBrowseView
     android:id="@+id/browseItemsContainer"
     android:accessibilityPaneTitle="@string/browseProducts" ... />

android:accessibilityPaneTitle

https://developer.android.google.cn/reference/android/R.attr#accessibilityPaneTitle

装饰性元素

如果界面中某个元素的存在只是为了让内容看起来间距合理或布局美观,请将其 android:contentDescription 属性设为 "null":

https://developer.android.google.cn/reference/android/view/View#attr_android:contentDescriptionandroid:contentDescription

如果应用仅支持搭载 Android 4.1 (API 级别 16) 或更高版本的设备,您可以将这些纯装饰性元素的 android:importantForAccessibility 属性设为 "no"。

扩展系统微件

要点: 在设计应用的界面时,请使用或扩展位于 Android 类层次结构中尽可能靠下位置的系统微件。位于层次结构最下方的系统微件已经具备应用所需的大多数无障碍功能。扩展系统提供的这些微件比根据更通用的 ViewViewCompatCanvas CanvasCompat 类创建您自己的微件更容易。

如果您必须直接扩展 ViewCanvas (这可能是高度个性化体验或游戏关卡所必需的),请参阅让自定义视图使用起来更没有障碍。

View

https://developer.android.google.cn/reference/kotlin/android/view/View

ViewCompat

https://developer.android.google.cn/reference/kotlin/androidx/core/view/ViewCompat

Canvas

https://developer.android.google.cn/reference/kotlin/android/graphics/Canvas

CanvasCompat

https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/canvas/CanvasCompat.java

让自定义视图使用起来更没有障碍

https://developer.android.google.cn/guide/topics/ui/accessibility/custom-views

本部分介绍了如何实现一种特殊类型的 Switch,称为 TriSwitch。TriSwitch 对象的工作方式与 Switch 对象类似,不同之处在于,TriSwitch 的每个实例允许用户在 3 种可能的状态之间切换。

Switch

https://developer.android.google.cn/reference/android/widget/Switch

从类层次结构最下方扩展

Switch 对象从其层次结构中的几个框架界面类继承一些属性:

View
↳ TextView
  ↳ Button
    ↳ CompoundButton
      ↳ Switch

新的 TriSwitch 类最好直接从 Switch 类扩展。这样,Android 无障碍功能框架就可以提供 TriSwitch 类所需的大多数无障碍功能:

  • 无障碍操作: 告知系统无障碍服务如何模拟在 TriSwitch 对象上执行的各种可能的用户输入。(继承自 View。)
  • 无障碍事件: 告知无障碍服务当屏幕刷新或更新时,TriSwitch 对象的外观会发生的各种可能的变化方式。(继承自 View。)
  • 特征: 有关每个 TriSwitch 对象的详细信息,例如其显示的任何文字的内容。(继承自 TextView。)
  • 状态信息: TriSwitch 对象的当前状态的说明,如 "选中" 或 "未选中"。(继承自 CompoundButton。)
  • 状态的文字说明: 文字类说明,解释了各种状态的含义。(继承自 Switch。)

继承自 Switch 及其父类的这种聚合行为几乎就是 TriSwitch 对象的预期行为。因此,您的实现可以着重于将可能的状态数从 2 种扩展到 3 种。

定义自定义事件

当您扩展某个系统微件时,可能会改变用户与该微件互动方式的某一方面。请务必定义这些互动变化,以便无障碍服务可以更新应用的微件,就像用户直接与微件互动一样。

一般准则是,对于您替换的每个基于视图的回调,您还需要通过替换 ViewCompat.replaceAccessibilityAction() 来重新定义相应的无障碍操作。在应用的测试中,您可以通过调用 ViewCompat.performAccessibilityAction() 来验证这些重新定义的操作的行为。

ViewCompat.replaceAccessibilityAction()

https://developer.android.google.cn/reference/androidx/core/view/ViewCompat#replaceAccessibilityAction(android.view.View,%20androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat,%20java.lang.CharSequence,%20androidx.core.view.accessibility.AccessibilityViewCommand)

ViewCompat.performAccessibilityAction()

https://developer.android.google.cn/reference/androidx/core/view/ViewCompat#performAccessibilityAction(android.view.View,%20int,%20android.os.Bundle)

此原则如何对 TriSwitch 对象起作用

与普通的 Switch 对象不同,点按 TriSwitch 对象可以循环切换 3 种可能的状态。因此,需要更新相应的 ACTION_CLICK 无障碍操作:

class TriSwitch(context: Context) : Switch(context) {
    // 0, 1, or 2.
    var currentState: Int = 0
        private set


    init {
        updateAccessibilityActions()
    }


    private fun updateAccessibilityActions() {
        ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
            action-label) {
            view, args -> moveToNextState()
        })
    }


    private fun moveToNextState() {
        currentState = (currentState + 1) % 3
    }
}

使用除颜色之外的提示

为了帮助有色觉缺陷的用户,请使用除颜色之外的提示区分应用屏幕中的界面元素。具体方法包括采用不同的形状或大小、提供文字或视觉图案,或者添加基于音频的反馈或基于轻触手势的触感反馈来表示元素的差异。

下图显示了一个 Activity 的两个版本。一个版本仅使用颜色区分工作流程中两种可能的操作。另一个版本采用了最佳做法: 除了颜色之外,还使用了形状和文字来突出两个选项之间的差异:

www.zeeklog.com  - 最佳实践 | 助您提升应用的无障碍功能

△ 仅使用颜色创建界面元素的示例 (左图),

以及使用颜色、形状和文字创建界面元素的示例 (右图)

让媒体内容使用起来更没有障碍

如果您开发的应用包含视频剪辑或音频录音等媒体内容,应设法为具有不同类型的无障碍功能需求的用户提供支持,让他们能够理解此类内容。特别是,我们建议您做到以下几点:

  • 添加可让用户暂停或停止播放媒体、调整音量以及切换字幕的控件。
  • 如果视频提供的信息对于完成工作流程至关重要,应以其他格式提供相同的内容,如转录内容。

其他资源

如需详细了解如何让您的应用使用起来更没有障碍,请参阅下面列出的其他资源:

Codelab: 基本的 Android 无障碍功能

https://developer.android.google.cn/codelabs/starting-android-accessibility#0

博文: 无障碍功能: 是否所有用户都能使用您的应用?

https://android-developers.googleblog.com/2012/04/accessibility-are-you-serving-all-your.html

欢迎您持续关注我们,及时了解更多开发技术和产品更新等资讯动态。

www.zeeklog.com  - 最佳实践 | 助您提升应用的无障碍功能

点击屏末 | 阅读原文 | 即刻了解无障碍功能更多相关内容


www.zeeklog.com  - 最佳实践 | 助您提升应用的无障碍功能
www.zeeklog.com  - 最佳实践 | 助您提升应用的无障碍功能
www.zeeklog.com  - 最佳实践 | 助您提升应用的无障碍功能

Read more

60个“特征工程”计算函数(Python代码)

60个“特征工程”计算函数(Python代码)

转自:coggle数据科学 近期一些朋友询问我关于如何做特征工程的问题,有没有什么适合初学者的有效操作。 特征工程的问题往往需要具体问题具体分析,当然也有一些暴力的策略,可以在竞赛初赛前期可以带来较大提升,而很多竞赛往往依赖这些信息就可以拿到非常好的效果,剩余的则需要结合业务逻辑以及很多其他的技巧,此处我们将平时用得最多的聚合操作罗列在下方。 最近刚好看到一篇文章汇总了非常多的聚合函数,就摘录在下方,供许多初入竞赛的朋友参考。 聚合特征汇总 pandas自带的聚合函数 * 其它重要聚合函数 其它重要聚合函数&分类分别如下。 def median(x):     return np.median(x) def variation_coefficient(x):     mean = np.mean(x)     if mean != 0:         return np.std(x) / mean     else:         return np.nan def variance(x):     return

By Ne0inhk
90w,确实可以封神了!

90w,确实可以封神了!

要说24年一定最热的技术,还得是AIGC! 前段时间阿里旗下的开源项目,登上GitHub热榜! AI大热,如今ChatGPT的优异表现,必然会出现各种细分场景应用的工具软件,和大量岗位项目! 山雨欲来风满楼,强人工智能的出现,所有科技公司已经开始巨量扩招此领域的人才。算法的岗位,近三个月已经增长68%!这件事在HR届也是相当震撼的。 目前各行各业都不景气的市场,人工智能岗位却一直保持常青!甚至同属AI边缘岗都比其他岗薪资高40%! 与此同时,AI算法岗上岸也不简单,竞争激烈,好公司核心岗位不用说,谁都想去。 所以事实就是,想要上岸,门槛也逐渐变高,项目经历、实习经历都很重要,越早明白这个道理就越能提前建立起自己的优势。 但我在b站逛知识区的时候,经常看到有些同学,因为一些客观原因导致无法参加实习,这种情况下,如果你想提升背景,增加项目经历的话,可以试试这个《CV/NLP 算法工程师培养计划》。 目前已经有上千位同学通过该计划拿到offer了,最新一期学员就业薪资最高能拿到78K!年薪94w! 优势就是有BAT大厂讲师带领,手把手带做AI真实企业项目(包含CV、NLP等

By Ne0inhk
再见nohup!试试这个神器,Python Supervisor!

再见nohup!试试这个神器,Python Supervisor!

👇我的小册 45章教程:() ,原价299,限时特价2杯咖啡,满100人涨10元。 作者丨Ais137 https://juejin.cn/post/7354406980784373798 1. 概述 Supervisor 是一个 C/S 架构的进程监控与管理工具,本文主要介绍其基本用法和部分高级特性,用于解决部署持久化进程的稳定性问题。 2. 问题场景 在实际的工作中,往往会有部署持久化进程的需求,比如接口服务进程,又或者是消费者进程等。这类进程通常是作为后台进程持久化运行的。 一般的部署方法是通过 nohup cmd & 命令来部署。但是这种方式有个弊端是在某些情况下无法保证目标进程的稳定性运行,有的时候 nohup 运行的后台任务会因为未知原因中断,从而导致服务或者消费中断,进而影响项目的正常运行。 为了解决上述问题,通过引入 Supervisor 来部署持久化进程,提高系统运行的稳定性。 3. Supervisor 简介 Supervisor is a client/

By Ne0inhk
第一本给程序员看的AI Agent图书上市了!

第一本给程序员看的AI Agent图书上市了!

AI Agent火爆到什么程度? OpenAI创始人奥特曼预测,未来各行各业,每一个人都可以拥有一个AI Agent;比尔·盖茨在2023年层预言:AI Agent将彻底改变人机交互方式,并颠覆整个软件行业;吴恩达教授在AI Ascent 2024演讲中高赞:AI Agent是一个令人兴奋的趋势,所有从事AI开发的人都应该关注。而国内的各科技巨头也纷纷布局AI Agent平台,如:钉钉的AI PaaS、百度智能云千帆大模型平台等等。 Agent 是未来最重要的智能化工具。对于程序员来说,是时候将目光转向大模型的应用开发了,率先抢占AI的下一个风口AI Agent。 小异带来一本新书《大模型应用开发 动手做 AI Agent》,这本书由《GPT图解》的作者黄佳老师创作,从0到1手把手教你做AI Agent。现在下单享受5折特惠! ▼点击下方,即可5折起购书 有这样一本秘籍在手,程序员们这下放心了吧,让我们先来揭开 Agent 的神秘面纱。 AI Agent 面面观

By Ne0inhk