Чтобы помочь пользователям с потребностями в специальных возможностях, платформа Android позволяет создать службу специальных возможностей, которая может предоставлять пользователям контент из приложений, а также управлять приложениями от их имени.
Android предоставляет несколько служб доступности системы, в том числе следующие:
- TalkBack : помогает людям со слабым зрением или слепым. Он объявляет контент посредством синтезированного голоса и выполняет действия в приложении в ответ на жесты пользователя.
- Switch Access : помогает людям с двигательными нарушениями. Он выделяет интерактивные элементы и выполняет действия в ответ на нажатие пользователем кнопки. Это позволяет управлять устройством с помощью всего одной или двух кнопок.
Чтобы помочь людям с потребностями в специальных возможностях успешно использовать ваше приложение, ваше приложение должно следовать рекомендациям, описанным на этой странице и основанным на рекомендациях, описанных в разделе «Сделайте приложения более доступными» .
Каждый из этих рекомендаций, описанных в следующих разделах, может еще больше улучшить доступность вашего приложения:
- Элементы этикетки
- Пользователи должны иметь возможность понимать содержание и назначение каждого интерактивного и значимого элемента пользовательского интерфейса вашего приложения.
- Добавить действия по обеспечению доступности
- Добавляя действия по обеспечению доступности, вы можете позволить пользователям служб доступности выполнять важные пользовательские потоки в вашем приложении.
- Расширение системных виджетов
- Используйте элементы представлений, входящие в состав платформы, а не создавайте собственные представления. Классы представлений и виджетов платформы уже предоставляют большую часть специальных возможностей, необходимых вашему приложению.
- Используйте сигналы, отличные от цвета
- Пользователи должны иметь возможность четко различать категории элементов пользовательского интерфейса. Для этого используйте узоры и положение, а также цвет, чтобы выразить эти различия.
- Сделайте медиаконтент более доступным
- Добавьте описания к видео- или аудиоконтенту вашего приложения, чтобы пользователям, потребляющим этот контент, не приходилось полагаться исключительно на визуальные или звуковые сигналы.
Элементы этикетки
Важно предоставить пользователям полезные и описательные метки для каждого интерактивного элемента пользовательского интерфейса в вашем приложении. Каждая этикетка должна объяснять значение и назначение конкретного элемента. Программы чтения с экрана, такие как 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
. Более подробную информацию см. в следующем разделе.
Пары элементов, где один описывает другой
Обычно элемент EditText
имеет соответствующий объект View
, который описывает, что пользователи должны ввести в элемент EditText
. Вы можете указать эту связь, установив атрибут android:labelFor
объекта 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" ... />
Элементы в коллекции
При добавлении меток к элементам коллекции каждая метка должна быть уникальной. Таким образом, службы специальных возможностей системы могут ссылаться только на один экранный элемент при объявлении метки. Эта переписка позволяет пользователям узнать, когда они циклически перемещаются по пользовательскому интерфейсу или когда они перемещают фокус на элемент, который они уже обнаружили.
В частности, включайте дополнительный текст или контекстную информацию в элементы повторно используемых макетов, например в объекты 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" } }
Ява
public class MovieRating { private String title; private int starRating; // ... public String getTitle() { return title; } public int getStarRating() { return starRating; } } public class MyMovieRatingsAdapter extends RecyclerView.Adapter<MyAdapter.MyRatingViewHolder> { private MovieRating[] myData; public static class MyRatingViewHolder extends RecyclerView.ViewHolder { public ImageView ratingView; public MyRatingViewHolder(ImageView iv) { super(iv); ratingView = iv; } } @Override public void onBindViewHolder(MyRatingViewHolder holder, int position) { MovieRating ratingData = myData[position]; holder.ratingView.setContentDescription("Movie " + position + ": " + ratingData.getTitle() + ", " + ratingData.getStarRating() + " stars") } }
Группы связанного контента
Если ваше приложение отображает несколько элементов пользовательского интерфейса, образующих естественную группу, например сведения о песне или атрибуты сообщения, расположите эти элементы в контейнере, который обычно является подклассом ViewGroup
. Установите для атрибута android:screenReaderFocusable
объекта контейнера значение true
, а для атрибута android:focusable
каждого внутреннего объекта — значение false
. Таким образом, службы доступности могут представлять описания содержимого внутренних элементов одно за другим в одном объявлении. Такое объединение связанных элементов помогает пользователям вспомогательных технологий более эффективно находить информацию на экране.
Следующий фрагмент содержит части контента, которые связаны друг с другом, поэтому элемент контейнера, экземпляр 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>
Поскольку службы доступности объявляют описания внутренних элементов в одном предложении, важно, чтобы каждое описание было как можно короче, но при этом передавало значение элемента.
Примечание. Как правило, вам следует избегать создания описания контента для группы путем агрегирования текста ее дочерних элементов. Это делает описание группы хрупким, и когда текст дочернего элемента изменяется, описание группы может больше не соответствовать видимому тексту.
В контексте списка или сетки программа чтения с экрана может объединить текст дочерних текстовых узлов списка или элемента сетки. Лучше избегать изменения этого объявления.
Вложенные группы
Если интерфейс вашего приложения предоставляет многомерную информацию, например ежедневный список фестивальных событий, используйте атрибут 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 9 (уровень API 28) и более поздних версиях вы можете предоставлять удобные заголовки для панелей экрана. В целях доступности панель представляет собой визуально отдельную часть окна, например содержимое фрагмента. Чтобы службы специальных возможностей могли понять поведение панели как окна, дайте панелям вашего приложения описательные заголовки. Службы специальных возможностей могут затем предоставлять пользователям более подробную информацию при изменении внешнего вида или содержимого панели.
Чтобы указать заголовок панели, используйте атрибут 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:importantForAccessibility
значение "no"
.
Добавить действия по обеспечению доступности
Важно позволить пользователям служб специальных возможностей легко выполнять все пользовательские действия в вашем приложении. Например, если пользователь может провести пальцем по элементу в списке, это действие также может быть доступно службам специальных возможностей, чтобы у пользователей был альтернативный способ завершить тот же пользовательский поток.
Сделайте все действия доступными
Пользователю TalkBack, Voice Access или Switch Access могут потребоваться альтернативные способы выполнения определенных пользовательских потоков в приложении. Для действий, связанных с жестами, такими как перетаскивание или пролистывание, ваше приложение может отображать действия таким образом, чтобы они были доступны пользователям служб специальных возможностей.
Используя действия доступности , приложение может предоставить пользователям альтернативные способы выполнения действия.
Например, если ваше приложение позволяет пользователям проводить по элементу, вы также можете предоставить эту функциональность с помощью специального действия по обеспечению специальных возможностей, например так:
Котлин
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive) ) { _, _ -> // Same method executed when swiping on itemView archiveItem() true }
Ява
ViewCompat.addAccessibilityAction( // View to add accessibility action itemView, // Label surfaced to user by an accessibility service getText(R.id.archive), (view, arguments) -> { // Same method executed when swiping on itemView archiveItem(); return true; } );
With the custom accessibility action implemented, users can access the action through the actions menu.
Make available actions understandable
When a view supports actions such as touch & hold, an accessibility service such as TalkBack announces it as "Double tap and hold to long press."
This generic announcement doesn't give the user any context about what a touch & hold action does.
To make this announcement more descriptive, you can replace the accessibility action’s announcement like so:
Kotlin
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null )
Ява
ViewCompat.replaceAccessibilityAction( // View that contains touch & hold action itemView, AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_LONG_CLICK, // Announcement read by TalkBack to surface this action getText(R.string.favorite), null );
This results in TalkBack announcing "Double tap and hold to favorite," helping users understand the purpose of the action.
Extend system widgets
Note: When you design your app's UI, use or extend
system-provided widgets that are as far down Android's class hierarchy as
possible. System-provided widgets that are far down the hierarchy already
have most of the accessibility capabilities your app needs. It's easier
to extend these system-provided widgets than to create your own from the more
generic View
,
ViewCompat
,
Canvas
, and
CanvasCompat
classes.
If you must extend View
or Canvas
directly, which
might be necessary for a highly customized experience or a game level, see
Make custom views more
accessible.
This section uses the example of implementing a special type of
Switch
called TriSwitch
while following
best practices around extending system widgets. A TriSwitch
object works similarly to a Switch
object, except that each instance of
TriSwitch
allows the user to toggle among three possible states.
Extend from far down the class hierarchy
The Switch
object inherits from several framework UI classes in its hierarchy:
View ↳ TextView ↳ Button ↳ CompoundButton ↳ Switch
Лучше всего, чтобы новый класс TriSwitch
наследовался непосредственно от класса Switch
. Таким образом, платформа специальных возможностей Android обеспечивает большинство возможностей доступности, необходимых классу TriSwitch
:
- Действия доступности: информация для системы о том, как службы доступности могут эмулировать каждый возможный пользовательский ввод, выполняемый над объектом
TriSwitch
. (Унаследовано отView
.) - События доступности: информация для служб доступности обо всех возможных способах изменения внешнего вида объекта
TriSwitch
при обновлении или обновлении экрана. (Унаследовано отView
.) - Характеристики: сведения о каждом объекте
TriSwitch
, например, содержимое любого текста, который он отображает. (Унаследовано отTextView
.) - Информация о состоянии: описание текущего состояния объекта
TriSwitch
, например «проверено» или «не отмечено». (Унаследовано отCompoundButton
.) - Текстовое описание состояния: текстовое объяснение того, что представляет собой каждое состояние. (Унаследовано от
Switch
.)
Такое поведение Switch
и его суперклассов практически такое же, как и для объектов TriSwitch
. Следовательно, ваша реализация может быть сосредоточена на расширении количества возможных состояний с двух до трех.
Определите пользовательские события
Расширяя системный виджет, вы, вероятно, меняете аспект взаимодействия пользователей с этим виджетом. Важно определить эти изменения взаимодействия, чтобы службы специальных возможностей могли обновлять виджет вашего приложения, как если бы пользователь напрямую взаимодействовал с виджетом.
Общая рекомендация заключается в том, что для каждого обратного вызова на основе представления, который вы переопределяете, вам также необходимо переопределить соответствующее действие доступности, переопределив ViewCompat.replaceAccessibilityAction()
. В тестах вашего приложения вы можете проверить поведение этих переопределенных действий, вызвав ViewCompat.performAccessibilityAction()
.
Как этот принцип может работать для объектов TriSwitch
В отличие от обычного объекта Switch
, касание объекта TriSwitch
переключает три возможных состояния. Поэтому соответствующее действие доступности 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 } }
Ява
public class TriSwitch extends Switch { // 0, 1, or 2 private int currentState; public int getCurrentState() { return currentState; } public TriSwitch() { updateAccessibilityActions(); } private void updateAccessibilityActions() { ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK, action-label, (view, args) -> moveToNextState()); } private void moveToNextState() { currentState = (currentState + 1) % 3; } }
Используйте сигналы, отличные от цвета
Чтобы помочь пользователям с нарушениями цветового зрения, используйте сигналы, отличные от цвета, чтобы различать элементы пользовательского интерфейса на экранах вашего приложения. Эти методы могут включать в себя использование различных форм и размеров, текстовые или визуальные шаблоны, а также добавление звуковой или сенсорной (тактильной) обратной связи для обозначения различий между элементами.
На рисунке 1 показаны две версии действия. В одной версии используется только цвет, чтобы различать два возможных действия в рабочем процессе. Другая версия использует передовой опыт включения фигур и текста в дополнение к цвету, чтобы подчеркнуть различия между двумя вариантами:
Сделайте медиаконтент более доступным
Если вы разрабатываете приложение, включающее мультимедийный контент, например видеоклип или аудиозапись, постарайтесь помочь пользователям с различными типами потребностей в специальных возможностях понять этот материал. В частности, мы рекомендуем вам сделать следующее:
- Включите элементы управления, которые позволяют пользователям приостанавливать или останавливать воспроизведение мультимедиа, изменять громкость и переключать субтитры (подписи).
- Если видео содержит информацию, важную для выполнения рабочего процесса, предоставьте тот же контент в альтернативном формате, например в виде стенограммы.
Дополнительные ресурсы
Чтобы узнать больше о том, как сделать ваше приложение более доступным, посетите следующие дополнительные ресурсы: