作者简介:
何金源,腾讯Android手Q开发工程师,负责Android手Q无障碍优化工作,对Android无障碍系统原理及开发技术有深入了解。在MDCC 2016移动开发者大会上,何金源将发表《Android无障碍化原理及优化》的主题演讲,介绍Android系统中无障碍实现原理,总结Android手机QQ进行无障碍优化过程中遇到的问题及解决办法,以及如何实现自定义View无障碍化。本文为《程序员》原创文章,未经允许不得转载,更多精彩文章请订阅2016年《程序员》
Android江湖上一直流传着一部秘籍——Android无障碍宝典。传闻练成这部宝典,可在Android无障碍模式下,飞檐走壁,能人所不能。宝典分为三篇,分别是入门、进阶和高级,由浅入深,全面展示无障碍的基本方法及扩展应用。
Android应用无障碍化,目的是为视觉障碍或其他有障碍的用户提供更好的服务。在无障碍模式下,用户的操作方式与平常不同,比如:
选择(Hover)一个元素:单击
点击(Click)一个元素:双击
滚动:双指往上、下、左、右
选择上或下一个项目:单指往上、下、左、右
快速回到主画面:单指上滑+左滑
返回键:单指下滑+左滑
最近画面键:单指左滑+上滑
通知栏:单指右滑+下滑
此外,还需要理解在无障碍模式下“无障碍焦点”这个概念。如图1所示,界面上以绿色方框来表示目前获得无障碍焦点的View。拥有无障碍焦点的View,会被TalkBack服务识别,TalkBack会从View中取出相关的无障碍内容,然后提示给用户。
有了对无障碍模式初步的了解,就可以正式开始学习如何为应用无障碍化。
入门篇
为View添加ContentDescription
UI上的可操作元素都应该添加上ContentDescription, 当此元素获得无障碍焦点时,TalkBack服务就取出View的提示语(contentDescription),并朗读出来。
添加ContentDescription有两种方法,第一种是通过在XML布局中设置android:contentDescripton属性,如:
<button android:id="”@+id/pause_button”" android:src="”@drawable/pause”" android:contentdescription="”@string/pause”/"></button>
但是很多情况下,View的内容描述会根据不同情景需要而改变,比如CheckBox按钮是否被选中,以及ListView中item的内容描述等。这种则需要在代码中使用setContentDescription方法,如:
String contentDescription = "已选中 " + strValues[position];
label.setContentDescription(contentDescription);
设置无障碍焦点
UI上的元素,有的默认带有无障碍焦点,如Button、CheckBox等标准控件,有的如果不设置contentDescription是默认没有无障碍焦点。在开发应用过程中,还会遇到一些UI元素,是不希望它获取无障碍焦点的。以下方法可以改变元素的无障碍焦点:
public void setAccessibilityFocusable(View view, boolean focused){
if(android.os.Build.VERSION.SDK_INT >= 16){
if(focused){
ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
}else{
ViewCompat.setImportantForAccessibility(view, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
}
}
}
IMPORTANT_FOR_ACCESSIBILITY_YES表示这个元素应该有无障碍焦点,会被TalkBack服务读出描述内容;IMPORTANT_FOR_ACCESSIBILITY_NO表示屏蔽元素的无障碍焦点,手指滑动遍历及触摸此元素,都不会获得无障碍焦点,TalkBack服务也不会读出其描述内容。
发出无障碍事件
IMPORTANT_FOR_ACCESSIBILITY_YES表示这个元素应该有无障碍焦点,会被TalkBack服务读出描述内容;IMPORTANT_FOR_ACCESSIBILITY_NO表示屏蔽元素的无障碍焦点,手指滑动遍历及触摸此元素,都不会获得无障碍焦点,TalkBack服务也不会读出其描述内容。
view.postDelayed(new Runnable() {
@Override
public void run(