让应用无障碍

Applications built for Android are more accessible to users with visual, physical or age-related limitations when those users activate accessibility services and features on a device. These services make your application more accessible even if you do not make any accessibility changes to your code. However, there are steps you should take to optimize the accessibility of your application and ensure a pleasant experience for all your users.

当视觉、肢残和老龄化用户激活设备中的无障碍服务和特性时,Android应用将会更加无障碍。无障碍服务让应用更加无障碍,即使在代码中不做任何的无障碍修改。但是,需要采取以下步骤来评估应用的无障碍性能,确保所有用户都有愉快的使用体验。

Making sure your application is accessible to all users requires only a few steps, particularly when you create your user interface with the components provided by the Android framework. If you use only the standard components for your application, the steps are:

保证所有用户的无障碍体验需要做到以下几步,特别是使用Android框架提供的组件创建用户界面时。如果应用只使用标准组件,步骤如下:

  1. Add descriptive text to user interface controls in your application using the android:contentDescription attribute. Pay particular attention to ImageButton, ImageView and CheckBox.
    使用android:contentDescription属性为应用中的交互控件添加描述性文本,特别是ImageButtonImageViewCheckBox
  2. Make sure that all user interface elements that can accept input (touches or typing) can be reached with a directional controller, such as a trackball, D-pad (physical or virtual) or navigation gestures .
    保证所有可以接收输入(触摸和输入)的用户界面元素都可以使用定向控制到达,例如:轨迹球、D-pad(物理或虚拟)、导航手势
  3. Make sure that audio prompts are always accompanied by another visual prompt or notification, to assist users who are deaf or hard of hearing.
    保证在音频反馈的同时伴有视觉反馈或通知,帮助听障用户使用应用。
  4. Test your application using only accessibility navigation services and features. Turn on TalkBack and Explore by Touch, and then try using your application using only directional controls. For more information on testing for accessibility, see the Accessibility Testing Checklist.
    使用无障碍导航服务和特性测试应用。打开TalkBack触摸浏览(Explore by Touch),然后尝试使用定向控制操作应用。更多无障碍测试信息,详见无障碍测试清单( Accessibility Testing Checklist)。

If you build custom controls that extend the View class, you must complete some additional work to make sure your components are accessible. This document discusses how to make custom view controls compatible with accessibility services.

如果自定义控件继承了View类,需要另外的工作来保证组件无障碍。该章节讨论的是怎样让自定义控件拥有无障碍特性。

Note: The implementation steps in this document describe the requirements for making your application accessible for users with blindness or low-vision. Be sure to review the requirements for serving users who are deaf and hard of hearing in the Accessibility Developer Checklist.

注意:该章节的实现步骤描述了为视障用户对应用进行无障碍改造的需求。在无障碍开发清单(Accessibility Developer Checklist)中需要复查视障用户的无障碍需求。

标记用户界面元素

Many user interface controls depend on visual cues to indicate their meaning and usage. For example, a note-taking application might use an ImageButton with a picture of a plus sign to indicate that the user can add a new note. An EditText component may have a label near it that indicates its purpose. A user with impaired vision can't see these cues well enough to follow them, which makes them useless.

很多用户界面控件依靠视觉提示告知用户含义和作用。例如:一个记事本程序可能会使用一个带有加号图片的ImageButton来提示用户可以通过它添加一个新的记录。或者,一个EditText元素的附近可能会有一个标签来提示目的。视障用户不能清晰看到这些提示并遵循它们,导致这些提示无效。

You can make these controls more accessible with the android:contentDescription XML layout attribute. The text in this attribute does not appear on screen, but if the user enables accessibility services that provide audible prompts, then when the user navigates to that control, the text is spoken.

可以使用android:contentDescription XML布局属性来让这些控件更加无障碍。该属性中的文本不会出现在屏幕上,但如果用户启用了可以提供音频反馈的无障碍服务,当用户导航到这些控件的时候,描述文本将会被读出。

For this reason, set the android:contentDescription attribute for every ImageButton, ImageView, CheckBox in your application's user interface, and add descriptions to any other input controls that might require additional information for users who are not able to see it.

因此,在应用的用户界面中需要为每个ImageButtonImageViewCheckBox控件设置android:contentDescription属性,同时也需要为视障用户在那些可能需要额外信息的输入控件中添加描述文本。

For example, the following ImageButton sets the content description for the plus button to the add_note string resource, which could be defined as “Add note" for an English language interface:

例如,下面的ImageButton使用add_note字符串资源为加号按钮设置内容描述,该资源在英文界面可能被定义为“Add note”:

<ImageButton
    android:id=”@+id/add_note_button”
    android:src=”@drawable/add_note”
    android:contentDescription=”@string/add_note”/>

By including the description, an accessibility service that provides spoken feedback can announce "Add note" when a user moves focus to this button or hovers over it.

通过给图像按钮添加描述文本,当用户将焦点移到该按钮,或者鼠标悬停时,提供语音反馈的无障碍服务可以读出“Add note”。

Note: For EditText fields, provide an android:hint attribute instead of a content description, to help users understand what content is expected when the text field is empty. When the field is filled, TalkBack reads the entered content to the user, instead of the hint text.

注意:对于EditText区域,提供android:hint属性代替内容描述,文本区域为空的时候此属性帮助用户理解应该输入什么样的内容。当文本区域填充上内容,TalkBack将会读出输入的文本,而不会读出提示文本。

启用焦点导航

Focus navigation allows users with disabilities to step through user interface controls using a directional controller. Directional controllers can be physical, such as a trackball, directional pad (D-pad) or arrow keys, or virtual, such as the Eyes-Free Keyboard, or the gestures navigation mode available in Android 4.1 and higher. Directional controllers are a primary means of navigation for many Android users.

焦点导航允许残障用户使用定向控制器一步步的浏览用户界面控件。定向控制器可以是物理的,如轨迹球、定向垫(D-pad)、方向键,或虚拟的,如非视觉键盘( Eyes-Free Keyboard)、和Android4.1以及以上可用的手势导航。定向控制器是很多Android用户导航的首选方式。

To ensure that users can navigate your application using only a directional controller, verify that all user interface (UI) input controls in your application can be reached and activated without using the touchscreen. You should also verify that clicking with the center button (or OK button) of a directional controller has the same effect as touching a control that already has focus. For information on testing directional controls, see Testing focus navigation.

为了保证用户可以使用定向控制器导航应用,需要验证应用中所有用户界面输入控件,在不使用触屏的情况下可以到达和激活。应该验证点击定向控制器的中心按钮(或OK按钮)和触屏的触摸操作有同样的效果。更多关于测试定向控制的信息,详见测试焦点导航

启用视图焦点

A user interface element is reachable using directional controls when its android:focusable attribute is set to true. This setting allows users to focus on the element using the directional controls and then interact with it. The user interface controls provided by the Android framework are focusable by default and visually indicate focus by changing the control’s appearance.

当用户界面元素的android:focusable属性设置为true时,可以使用定向控制到达该元素。该设置允许用户使用定向控制聚焦元素并与之交互。 Android框架提供的用户界面控件默认可聚焦,并通过改变控件的外观可直观表明其聚焦。

Android provides several APIs that let you control whether a user interface control is focusable and even request that a control be given focus:

Android提供了几个API让开发者决定用户界面控件是否可聚焦,甚至请求给控件赋予焦点:

If a view is not focusable by default, you can make it focusable in your layout file by setting the android:focusable attribute to true or by calling the its setFocusable() method.

如果视图不是默认聚焦,可以在布局文件中设置android:focusable属性为true,或者调用setFocusable()方法让视图可聚焦。

控制焦点顺序

When users navigate in any direction using directional controls, focus is passed from one user interface element (view) to another, as determined by the focus order. This order is based on an algorithm that finds the nearest neighbor in a given direction. In rare cases, the algorithm may not match the order that you intended or may not be logical for users. In these situations, you can provide explicit overrides to the ordering using the following XML attributes in your layout file:

当用户在任何方向使用定向控制器导航时,焦点从一个用户界面元素(视图)传递到另一个由焦点顺序指定的用户界面元素(视图)。焦点顺序是以一种在某一特定方向上寻找相邻元素的算法为基础的。在极少数情况下,默认的算法可能不匹配开发者定义的顺序,或可能对于用户不符合逻辑。在这些情况下,可以在布局文件中使用下列的xml属性明确地覆盖焦点顺序:

android:nextFocusDown
Defines the next view to receive focus when the user navigates down.
当用户向下导航时,定义下一个接收焦点的视图;
android:nextFocusLeft
Defines the next view to receive focus when the user navigates left.
当用户向左导航时,定义下一个接收焦点的视图;
android:nextFocusRight
Defines the next view to receive focus when the user navigates right.
当用户向右导航时,定义下一个接收焦点的视图;
android:nextFocusUp
Defines the next view to receive focus when the user navigates up.
当用户向上导航时,定义下一个接收焦点的视图。

The following example XML layout shows two focusable user interface elements where the android:nextFocusDown and android:nextFocusUp attributes have been explicitly set. The TextView is located to the right of the EditText. However, since these properties have been set, the TextView element can now be reached by pressing the down arrow when focus is on the EditText element:

下面的XML布局示例中展示了两个可聚焦的用户界面元素,这两个元素的android:nextFocusDownandroid:nextFocusUp属性被明确地设置。TextView位于EditText的右边。但是,因为设置了这些属性,当EditText聚焦时,按下下光标可以将焦点移到TextView元素上:

<LinearLayout android:orientation="horizontal"
        ... >
    <EditText android:id="@+id/edit"
        android:nextFocusDown=”@+id/text”
        ... />
    <TextView android:id="@+id/text"
        android:focusable=”true”
        android:text="Hello, I am a focusable TextView"
        android:nextFocusUp=”@id/edit”
        ... />
</LinearLayout>

When modifying focus order, be sure that the navigation works as expected in all directions from each user interface control and when navigating in reverse (to get back to where you came from).

当修改焦点顺序时,确保每一个用户界面控件的所有方向的导航能按照预期工作,尤其是反向导航的时候(从来的路径返回)。

Note: You can modify the focus order of user interface components at runtime, using methods such as setNextFocusDownId() and setNextFocusRightId().

注意:开发者可以使用诸如setNextFocusDownId()setNextFocusRightId()的方法,在程序运行的时候修改用户界面组件的聚焦顺序。

创建可访问自定义视图

If your application requires a custom view component, you must do some additional work to ensure that your custom view is accessible. These are the main tasks for ensuring the accessibility of your view:

如果应用需要一个自定义视图组件,开发者必须做一些额外的工作来确保自定义视图是可访问的。这些都是确保视图可访问性的主要任务:

处理定向控制器的点击

On most devices, clicking a view using a directional controller sends a KeyEvent with KEYCODE_DPAD_CENTER to the view currently in focus. All standard Android views already handle KEYCODE_DPAD_CENTER appropriately. When building a custom View control, make sure this event has the same effect as touching the view on the touchscreen.

在大多数的Android设备上,使用定向控制器单击视图会发送一个带有KEYCODE_DPAD_CENTERKeyEvent事件到当前的焦点视图。所有的标准Android视图已经适当地处理KEYCODE_DPAD_CENTER。当构建一个自定义View控件,确保这个事件的效果跟在触摸屏上触摸视图的效果一样。

Your custom control should also treat the KEYCODE_ENTER event the same as KEYCODE_DPAD_CENTER. This approach makes interaction from a full keyboard much easier for users.

自定义控件也应该将KEYCODE_ENTER事件作为KEYCODE_DPAD_CENTER事件处理,这种方法使全键盘用户的交互更加容易。

实现无障碍API方法

Accessibility events are messages about users interaction with visual interface components in your application. These messages are handled by Accessibility Services, which use the information in these events to produce supplemental feedback and prompts. In Android 4.0 (API Level 14) and higher, the methods for generating accessibility events have been expanded to provide more detailed information than the AccessibilityEventSource interface introduced in Android 1.6 (API Level 4). The expanded accessibility methods are part of the View class as well as the View.AccessibilityDelegate class. The methods are as follows:

无障碍事件是用户在应用中与视觉界面元素的交互消息。这些消息是由无障碍服务(Accessibility Services)处理的,这些服务使用这些事件中的信息去产生补充反馈和提示。在Android4.0(API级别14)和更高的系统中,生成无障碍事件的方法被扩展到比Android1.6(API级别4)的AccessibilityEventSource提供更多的详细信息。扩展无障碍方法是View类和View.AccessibilityDelegate类的一部分。这些方法如下:

sendAccessibilityEvent()
(API Level 4) This method is called when a user takes action on a view. The event is classified with a user action type such as TYPE_VIEW_CLICKED. You typically do not need to implement this method unless you are creating a custom view.
(API级别4)当用户操作视图时,这个方法被调用。该事件使用用户操作类型进行分类,例如TYPE_VIEW_CLICKED。开发者一般不需要实现这个方法,除非创建了自定义视图。
sendAccessibilityEventUnchecked()
(API Level 4) This method is used when the calling code needs to directly control the check for accessibility being enabled on the device (AccessibilityManager.isEnabled()). If you do implement this method, you must perform the call as if accessibility is enabled, regardless of the actual system setting. You typically do not need to implement this method for a custom view.
(API级别4)当调用的代码需要直接检查设备是否激活无障碍特性(AccessibilityManager.isEnabled())的时候,调用该方法。如果实现该方法,必须执行无障碍激活的检查,而不管系统真正的设置。一般的,不需要为自定义视图实现该方法。
dispatchPopulateAccessibilityEvent()
(API Level 4) The system calls this method when your custom view generates an accessibility event. As of API Level 14, the default implementation of this method calls onPopulateAccessibilityEvent() for this view and then the dispatchPopulateAccessibilityEvent() method for each child of this view. In order to support accessibility services on revisions of Android prior to 4.0 (API Level 14) you must override this method and populate getText() with descriptive text for your custom view, which is spoken by accessibility services, such as TalkBack.
(API级别4)当自定义视图产生无障碍事件时,系统调用这个方法。在API级别14中,该方法的默认实现是为视图调用onPopulateAccessibilityEvent(),然后为该视图的子元素调用 dispatchPopulateAccessibilityEvent()。为了支持Android4.0(API级别14)之前的版本,开发者必须重写该方法,使用自定义视图的描述性文本填充getText(),描述性文本将会被无障碍服务读出,例如TalkBack。
onPopulateAccessibilityEvent()
(API Level 14) This method sets the spoken text prompt of the AccessibilityEvent for your view. This method is also called if the view is a child of a view which generates an accessibility event.
(API级别14)该方法为视图的AccessibilityEvent设置朗读文本提示。如果视图是另一个生成无障碍事件视图的子视图,调用该方法。

Note: Modifying additional attributes beyond the text within this method potentially overwrites properties set by other methods. While you can modify attributes of the accessibility event with this method, you should limit these changes to text content, and use the onInitializeAccessibilityEvent() method to modify other properties of the event.

注意: 通过该方法修改文本以外的属性可能会被其他方法重写。虽然在该方法中开发者可以修改无障碍事件的属性,但是应该做到这些改变仅限于文本内容,并使用onInitializeAccessibilityEvent()方法修改事件的其他属性。

Note: If your implementation of this event completely overrides the output text without allowing other parts of your layout to modify its content, then do not call the super implementation of this method in your code.

注意: 如果该事件的实现完全重写了输出文本,而不允许布局的其他部分修改这个内容,不要在代码中调用该方法的父类实现。

onInitializeAccessibilityEvent()
(API Level 14) The system calls this method to obtain additional information about the state of the view, beyond text content. If your custom view provides interactive control beyond a simple TextView or Button, you should override this method and set the additional information about your view into the event using this method, such as password field type, checkbox type or states that provide user interaction or feedback. If you do override this method, you must call its super implementation and then only modify properties that have not been set by the super class.
(API级别14)系统调用此方法来获取超出文本内容的视图状态的附加信息。如果自定义视图提供简单TextViewButton以外的交互控制,开发者应该重写该方法,并且使用该方法设置该视图的额外信息到事件中,如密码区域类型,复选框类型或提供用户交互或反馈的状态。如果重写这个方法,开发者必须调用它父类的实现方法,然后只修改那些父类中尚未设置的属性。
onInitializeAccessibilityNodeInfo()
(API Level 14) This method provides accessibility services with information about the state of the view. The default View implementation has a standard set of view properties, but if your custom view provides interactive control beyond a simple TextView or Button, you should override this method and set the additional information about your view into the AccessibilityNodeInfo object handled by this method.
(API级别14)该方法为无障碍服务提供视图的状态信息。默认View的实现包含一组标准的视图属性,但是如果自定义视图提供了超出TextViewButton的交互,开发者应该重写该方法,并在AccessibilityNodeInfo对象中设置视图的额外信息,该对象被该方法处理。
onRequestSendAccessibilityEvent()
(API Level 14) The system calls this method when a child of your view has generated an AccessibilityEvent. This step allows the parent view to amend the accessibility event with additional information. You should implement this method only if your custom view can have child views and if the parent view can provide context information to the accessibility event that would be useful to accessibility services.
(API级别14)当视图中的一个子视图生成AccessibilityEvent时,系统调用这个方法。该步骤允许父视图使用额外信息修复无障碍事件。当自定义视图有子视图,且其父视图可以为无障碍事件提供对无障碍服务有用的上下文信息的时候,此时开发者应该实现这个方法。

In order to support these accessibility methods for a custom view, you should take one of the following approaches:

为了在自定义视图中支持这些无障碍方法,应该采取下列方法中的一种:

  • If your application targets Android 4.0 (API level 14) and higher, override and implement the accessibility methods listed above directly in your custom view class.
    如果应用程序目标版本是Android4.0(API级别14)或更高,就直接在自定义视图类中重写并实现上面列出的无障碍方法。
  • If your custom view is intended to be compatible with Android 1.6 (API Level 4) and above, add the Android Support Library, revision 5 or higher, to your project. Then, within your custom view class, call the ViewCompat.setAccessibilityDelegate() method to implement the accessibility methods above. For an example of this approach, see the Android Support Library (revision 5 or higher) sample AccessibilityDelegateSupportActivity in (<sdk>/extras/android/support/v4/samples/Support4Demos/)
    如果自定义视图的目的是要兼容Android1.6(API级别4)及以上,在项目中添加版本5或更高的支持库。然后,在自定义视图类中,调用ViewCompat.setAccessibilityDelegate()方法来实现上面的无障碍方法。对于这种方法的示例,请参阅支持库(版本5或更高)AccessibilityDelegateSupportActivity例子在(<sdk>/extras/android/support/v4/samples/Support4Demos/)。

In either case, you should implement the following accessibility methods for your custom view class:

在任何一种情况下,需要为自定义视图类实现下面的无障碍方法:

For more information about implementing these methods, see Populating Accessibility Events.

更多信息实现这些方法,请参阅填充无障碍事件(Populating Accessibility Events)。

发送无障碍事件

Depending on the specifics of your custom view, it may need to send AccessibilityEvent objects at a different times or for events not handled by the default implementation. The View class provides a default implementation for these event types:

根据自定义视图的特性,不是由默认实现处理的事件,可能需要在不同时刻发送AccessibilityEvent对象。View类为这些事件类型提供了默认的实现方法:

Note: Hover events are associated with the Explore by Touch feature, which uses these events as triggers for providing audible prompts for user interface elements.

注意:悬停(Hover)事件与触摸浏览相关联,触摸浏览使用这些事件作为触发器,为用户界面元素提供音频反馈。

In general, you should send an AccessibilityEvent whenever the content of your custom view changes. For example, if you are implementing a custom slider bar that allows a user to select a numeric value by pressing the left or right arrows, your custom view should emit an event of type TYPE_VIEW_TEXT_CHANGED whenever the slider value changes. The following sample code demonstrates the use of the sendAccessibilityEvent() method to report this event.

一般来说,每当自定义视图的内容发生变化时,应该发送一个AccessibilityEvent事件。例如,如果创建了一个自定义的滑动条,用户可以按下左边或右边的箭头选择数值,当滑动条的值发生改变时,自定义视图应该发出一个TYPE_VIEW_TEXT_CHANGED 类型的事件。下面的示例代码演示了使用sendAccessibilityEvent()方法报告该事件:

@Override
public boolean onKeyUp (int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
        mCurrentValue--;
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
        return true;
    }
    ...
}

填充无障碍事件

Each AccessibilityEvent has a set of required properties that describe the current state of the view. These properties include things such as the view’s class name, content description and checked state. The specific properties required for each event type are described in the AccessibilityEvent reference documentation. The View implementation provides default values for these properties. Many of these values, including the class name and event timestamp, are provided automatically. If you are creating a custom view component, you must provide some information about the content and characteristics of the view. This information may be as simple as a button label, but may also include additional state information that you want to add to the event.

每个AccessibilityEvent有一组必需的属性,这些属性描述当前视图的状态。这些属性包括视图类名称、内容描述和检查状态等信息。每个事件类型必须的特定属性被描述在AccessibilityEvent参考文档中。View实现提供这些属性的默认值。包含类名和事件时间标记在内的很多值会被自动提供。如果正在创建一个自定义视图组件,必须提供一些关于视图内容和特性的信息。这些信息可能是简单的按钮标签,但是也可能包含想要添加到事件中的额外的状态信息。

The minimum requirement for providing information to accessibility services with a custom view is to implement dispatchPopulateAccessibilityEvent(). This method is called by the system to request information for an AccessibilityEvent and makes your custom view compatible with accessibility services on Android 1.6 (API Level 4) and higher. The following example code demonstrates a basic implementation of this method.

一个自定义视图为无障碍服务提供信息的最低要求是实现dispatchPopulateAccessibilityEvent()方法。系统调用这个方法,为AccessibilityEvent请求信息,让自定义视图兼容Android1.6(API级别4)以上的无障碍服务。下面的示例代码展示了该方法的基本实现:

@Override
public void dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
    super.dispatchPopulateAccessibilityEvent(event);
    //在API级别14及以上版本中,调用父类实现将文本填充到事件;
	//在低于API级别14的系统中,检查事件的文本内容,并为自定义视图添加合适的文本描述;
    CharSequence text = getText();
    if (!TextUtils.isEmpty(text)) {
        event.getText().add(text);
    }
}

For Android 4.0 (API Level 14) and higher, use the onPopulateAccessibilityEvent() and onInitializeAccessibilityEvent() methods to populate or modify the information in an AccessibilityEvent. Use the onPopulateAccessibilityEvent() method specifically for adding or modifying the text content of the event, which is turned into audible prompts by accessibility services such as TalkBack. Use the onInitializeAccessibilityEvent() method for populating additional information about the event, such as the selection state of the view.

在Android 4.0(API级别14)和更高的系统中,使用onPopulateAccessibilityEvent()onInitializeAccessibilityEvent()方法来填充或修改AccessibilityEvent事件中的信息。onPopulateAccessibilityEvent()方法可专门用来为事件添加或修改文本内容,这些信息会被如TalkBack的无障碍服务转化为音频反馈。使用onInitializeAccessibilityEvent()方法添加事件的其他信息,比如视图的选择状态。

In addition, implement the onInitializeAccessibilityNodeInfo() method. The AccessibilityNodeInfo objects populated by this method are used by accessibility services to investigate the view hierarchy that generated an accessibility event after receiving that event, to obtain a more detailed context information and provide appropriate feedback to users.

此外,还应该实现onInitializeAccessibilityNodeInfo()方法。该方法填充AccessibilityNodeInfo对象,视图层次在接收此事件后生成无障碍事件,无障碍服务使用AccessibilityNodeInfo对象访问该视图层次,获得更多的上下文信息并为用户提供合适的反馈。

The example code below shows how override these three methods by using ViewCompat.setAccessibilityDelegate(). Note that this sample code requires that the Android Support Library for API Level 4 (revision 5 or higher) is added to your project.

下面的示例代码显示了如何使用ViewCompat.setAccessibilityDelegate()重写这三种方法。注意,此示例代码要求添加API级别4(或更高)的Android支持库(Support Library)到项目。

ViewCompat.setAccessibilityDelegate(new AccessibilityDelegateCompat() {
    @Override
    public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
        super.onPopulateAccessibilityEvent(host, event);
	//调用父类实现来填充事件的文本。然后添加父类中不存在的文本。
	//常常只需要在自定义视图中添加这些文本。
        CharSequence text = getText();
        if (!TextUtils.isEmpty(text)) {
            event.getText().add(text);
        }
    }
    @Override
    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
        super.onInitializeAccessibilityEvent(host, event);
        //调用父类实现让父类设置事件属性。然后添加父类不支持的新属性。
        event.setChecked(isChecked());
    }
    @Override
    public void onInitializeAccessibilityNodeInfo(View host,
            AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);
		//调用父类实现让父类设置适当的info属性。然后添加父类不支持的属性(checkable and checked)。
        info.setCheckable(true);
        info.setChecked(isChecked());
       //经常只需要添加自定义视图的文本。
        CharSequence text = getText();
        if (!TextUtils.isEmpty(text)) {
            info.setText(text);
        }
    }
}

You can implement these methods directly in your custom view class. For another example of this approach, see the Android Support Library (revision 5 or higher) sample AccessibilityDelegateSupportActivity in (<sdk>/extras/android/support/v4/samples/Support4Demos/).

在Android 4.0(API级别14)和更高的应用程序中,可以在自定义视图类中直接实现这些方法。这种方法的另一个例子,请参阅Android支持库(Support Library)(版本5或更高)的示例,AccessibilityDelegateSupportActivity 样本在 (<sdk>/extras/android/support/v4/samples/Support4Demos/)。

提供自定义无障碍内容

In Android 4.0 (API Level 14), the framework was enhanced to allow accessibility services to inspect the containing view hierarchy of a user interface component that generates an accessibility event. This enhancement allows accessibility services to provide a much richer set of contextual information with which to aid users.

在Android4.0(API级别14)中,Android框架得到改善,可以允许无障碍服务访问可生成无障碍事件的用户界面组件包含的视图层次。此改善允许无障碍服务提供一组更丰富的可以帮助用户的上下文信息。

There are some cases where accessibility services cannot get adequate information from the view hierarchy. An example of this is a custom interface control that has two or more separately clickable areas, such as a calendar control. In this case, the services cannot get adequate information because the clickable subsections are not part of the view hierarchy.

在某些情况下,无障碍服务不能从视图层次中获得足够的信息。一个自定义界面控件样例包含两个以上的可点击区域,例如一个日历控件。这种情况下,无障碍服务无法获得足够的信息,因为可点击部分不是视图层次的一部分。

图1 可选择日期的自定义日历视图。

In the example shown in Figure 1, the entire calendar is implemented as a single view, so if you do not do anything else, accessibility services do not receive enough information about the content of the view and the user's selection within the view. For example, if a user clicks on the day containing 17, the accessibility framework only receives the description information for the whole calendar control. In this case, the TalkBack accessibility service would simply announce "Calendar" or, only slightly better, "April Calendar" and the user would be left to wonder what day was selected.

在图1所示的例子中,整个日历是作为独立View实现,因此如果不采取其他措施,无障碍服务就不能获得有关视图和视图中用户选择的足够信息。例如,如果用户点击了包含17的日期,无障碍框架只能接收到整个日历控件的描述信息。这种情况下,TalkBack无障碍服务会简单读出“日历”,或者稍好一些的读出“四月日历”,而用户将会不知道自己选择了哪天。

To provide adequate context information for accessibility services in situations like this, the framework provides a way to specify a virtual view hierarchy. A virtual view hierarchy is a way for application developers to provide a complementary view hierarchy to accessibility services that more closely matches the actual information on screen. This approach allows accessibility services to provide more useful context information to users.

在像这样的情况下,为了给无障碍服务提供足够的上下文信息,Android框架提供了一种方法——指定虚拟视图层次。应用开发者可以使用虚拟视图层次方法为无障碍服务提供一个附加视图层次,该层次能最大限度的接近屏幕上的真实信息。这种方法允许无障碍服务给用户提供更有用的上下文信息。

Another situation where a virtual view hierarchy may be needed is a user interface containing a set of controls (views) that have closely related functions, where an action on one control affects the contents of one or more elements, such as a number picker with separate up and down buttons. In this case, accessibility services cannot get adequate information because action on one control changes content in another and the relationship of those controls may not be apparent to the service. To handle this situation, group the related controls with a containing view and provide a virtual view hierarchy from this container to clearly represent the information and behavior provided by the controls.

另一个需要虚拟视图继承结构的情况是,用户界面包含一组功能密切相关的控件(视图),操作一个控件会影响一个或多个组内其他元素的内容,例如增加按钮和减少按钮分开的数值选择器。在这种情况下,无障碍服务无法获得足够的信息,因为一个控件的操作会改变另一个控件的内容,且无障碍服务无法获得这种关系。为了处理这种情况,将包含视图的相关控件进行分组,从该容器中提供虚拟视图继承,清楚呈现控件提供的信息和行为。

In order to provide a virtual view hierarchy for a view, override the getAccessibilityNodeProvider() method in your custom view or view group and return an implementation of AccessibilityNodeProvider. For an example implementation of this accessibility feature, see AccessibilityNodeProviderActivity in the ApiDemos sample project. You can implement a virtual view hierarchy that is compatible with Android 1.6 and later by using the Support Library with the ViewCompat.getAccessibilityNodeProvider() method and providing an implementation with AccessibilityNodeProviderCompat.

为了提供虚拟视图继承,在自定义视图或者视图组中重写getAccessibilityNodeProvider()方法,并返回AccessibilityNodeProvider的实现。该无障碍特性实现的一个例子,详见ApiDemos样例工程中的AccessibilityNodeProviderActivity。在Android1.6和以后的版本中,可以使用Support Library中的ViewCompat.getAccessibilityNodeProvider()方法,并提供AccessibilityNodeProviderCompat实现,就可以兼容虚拟视图继承。

处理自定义触摸事件

Custom view controls may require non-standard touch event behavior. For example, a custom control may use the onTouchEvent(MotionEvent) listener method to detect the ACTION_DOWN and ACTION_UP events and trigger a special click event. In order to maintain compatibility with accessibility services, the code that handles this custom click event must do the following:

自定义视图控件可能需要非标准的触摸事件行为。例如自定义控件可能使用onTouchEvent(MotionEvent)监听方法来检测ACTION_DOWNACTION_UP事件,并触发一个特殊的点击事件。为了保证无障碍服务的兼容性,处理自定义点击事件的代码必须如下:

  1. Generate an appropriate AccessibilityEvent for the interpreted click action.
    为解释点击操作生成适当的AccessibilityEvent
  2. Enable accessibility services to perform the custom click action for users who are not able to use a touch screen.
    启用无障碍服务来为不能使用触摸屏的用户执行自定义单击操作。

To handle these requirements in an efficient way, your code should override the performClick() method, which must call the super implementation of this method and then execute whatever actions are required by the click event. When the custom click action is detected, that code should then call your performClick() method. The following code example demonstrates this pattern.

要有效的处理这些需求,代码应该重写performClick()方法,需要调用该方法的父类实现,然后执行点击事件需要的任何操作。当检测到自定义点击操作时,代码应该调用performClick()。下列代码示例展示了这一模式:

class CustomTouchView extends View {

    public CustomTouchView(Context context) {
        super(context);
    }

    boolean mDownTouch = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        //监听向下向上触摸事件
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mDownTouch = true;
                return true;

            case MotionEvent.ACTION_UP:
                if (mDownTouch) {
                    mDownTouch = false;
                    performClick(); //调用该方法处理响应,启动无障碍服务为那些无法点击的用户执行操作。
                    return true;
                }
        }
        return false; //为其他触摸事件返回假。
    }

    @Override
    public boolean performClick() {
        //调用父类实现,父类会生成无障碍事件,并且在视图上调用onClick()监听器,如果任何;
        super.performClick();

        //在这里处理自定义点击操作

        return true;
    }
}

The pattern shown above makes sure that the custom click event is compatible with accessibility services by using the performClick() method to both generate an accessibility event and provide an entry point for accessibility services to act on behalf of a user to perform this custom click event.

上面的代码通过使用performClick()方法保证自定义点击事件与无障碍服务兼容,生成无障碍事件并且为无障碍服务提供入口,并代替用户执行自定义点击事件。

Note: If your custom view has distinct clickable regions, such as a custom calendar view, you must implement a virtual view hierarchy by overriding getAccessibilityNodeProvider() in your custom view in order to be compatible with accessibility services.

注意:如果自定义视图有不同的可点击区域,例如自定义日历视图,必须在自定义视图中重写getAccessibilityNodeProvider()实现虚拟视图继承(virtual view hierarchy),保证与无障碍服务兼容。

测试无障碍

Testing the accessibility of your application is an important part of ensuring your users have a great experience. You can test the most important accessibility features by using your application with audible feedback enabled and navigating within your application using only directional controls. For more information on testing accessibility in your application, see the Accessibility Testing Checklist.

测试应用的无障碍是保证良好用户体验的重要部分。开发者可以通过在应用程序启用语音反馈和仅使用定向控制在应用程序内导航来测试最重要的无障碍特性。更多无障碍测试信息,详见无障碍测试清单(Accessibility Testing Checklist)