Специальные возможности в Android
На этой странице описывается использование API специальных возможностей Android для создания приложений в соответствии с контрольным списком специальных возможностей. Ознакомьтесь со страницами специальных возможностей iOS и специальными возможностями OS X для других API платформ.
Описание элементов пользовательского интерфейса
Android предоставляет ContentDescription свойство, которое используется API-интерфейсами чтения с экрана, чтобы предоставить доступное описание назначения элемента управления.
Описание содержимого можно задать на C# или в файле макета AXML.
C#
Описание можно задать в коде для любой строки (или строкового ресурса):
saveButton.ContentDescription = "Save data";
Макет AXML
В XML-макетах используйте android:contentDescription атрибут :
Использование подсказки для TextView
Для EditText элементов управления и TextView для ввода данных используйте Hint свойство , чтобы предоставить описание ожидаемых входных данных (вместо ContentDescription ). При вводе какого-то текста сам текст будет «прочитан» вместо указания.
C#
Задайте свойство в коде Hint :
someText.Hint = "Enter some text"; // displays (and is "read") when control is empty
Макет AXML
В xml-файлах макета android:hint используйте атрибут :
LabelFor связывает входные поля с метками
Чтобы связать метку с элементом управления вводом данных, используйте свойство для LabelFor
C#
В C# задайте LabelFor для свойства идентификатор ресурса элемента управления, описываемого этим содержимым (обычно это свойство задается на метке и ссылается на некоторые другие входные элементы управления):
EditText edit = FindViewById (Resource.Id.editFirstName); TextView tv = FindViewById (Resource.Id.labelFirstName); tv.LabelFor = Resource.Id.editFirstName;
Макет AXML
В XML-коде макета android:labelFor используйте свойство для ссылки на идентификатор другого элемента управления:
Объявление о специальных возможностях
Используйте метод в AnnounceForAccessibility любом элементе управления представлением, чтобы сообщить пользователям об изменении события или состояния при включении специальных возможностей. Этот метод не требуется для большинства операций, где встроенное речевое сопровождение обеспечивает достаточную обратную связь, но его следует использовать там, где пользователю будет полезна дополнительная информация.
В приведенном ниже коде показан простой пример вызова AnnounceForAccessibility :
button.Click += delegate < button.Text = string.Format ("clicks!", count++); button.AnnounceForAccessibility (button.Text); >;
Изменение параметров фокуса
Навигация со специальными возможностями зависит от элементов управления, имеющих фокус, чтобы помочь пользователю понять, какие операции доступны. Android предоставляет Focusable свойство, которое может помечать элементы управления как специально способные получать фокус во время навигации.
C#
Чтобы элемент управления не получил фокус с помощью C#, присвойте свойству Focusable значение false :
label.Focusable = false;
Макет AXML
В XML-файлах макета android:focusable задайте атрибут :
Вы также можете управлять порядком фокусировки с помощью nextFocusDown атрибутов , nextFocusLeft , nextFocusRight , nextFocusUp которые обычно задаются в макете AXML. Используйте эти атрибуты, чтобы пользователи могли легко перемещаться по элементам управления на экране.
Специальные возможности и локализация
В приведенных выше примерах подсказка и описание содержимого задаются непосредственно в качестве отображаемого значения. Предпочтительнее использовать значения в Strings.xml файле, например:
Enter some text Save data
Ниже показано использование текста из файла строк в файлах макетов C# и AXML:
C#
Вместо использования строковых литералов в коде ищите переведенные значения из строковых файлов с помощью Resources.GetText :
someText.Hint = Resources.GetText (Resource.String.enter_info); saveButton.ContentDescription = Resources.GetText (Resource.String.save_info);
AXML
В макете xml-атрибуты специальных возможностей, такие как hint и contentDescription , можно задать в строковый идентификатор:
Преимущество хранения текста в отдельном файле заключается в том, что в вашем приложении можно предоставить несколько языковых переводов файла. Сведения о добавлении локализованных строковых файлов в проект приложения см. в руководстве по локализации Android.
Тестирование специальных возможностей
Выполните следующие действия , чтобы включить TalkBack и Explore by Touch для тестирования специальных возможностей на устройствах Android.
Возможно, потребуется установить TalkBack из Google Play, если он не отображается в разделе Специальные > возможности параметров.
Связанные ссылки
- Кросс-платформенные специальные возможности
- API специальных возможностей Android
Как проявляется contentDescription
В учебнике по Android’у несколько раз упоминается про параметр (и метод) contentDescription . К примеру, в разметке я его устанавливал в ImageView :
Но я никак не могу понять для чего это! На картинку и нажимал, и удерживал, но никаких эффектов, текста и тд. Так для чего же этот contentDescription и как он проявляется?
Отслеживать
задан 25 мар 2016 в 23:05
user189127 user189127
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Это для слабовидящих. Текст в значении этого аттрибута будет озвучен системой при нажатии на картинку в случае, если в настройках устройства включена соответствующая опция.
Озвучка идёт чрез гугловое приложение
Отслеживать
ответ дан 25 мар 2016 в 23:12
69.8k 9 9 золотых знаков 66 66 серебряных знаков 123 123 бронзовых знака
Я бы хотел добавить, что это очень важный аттрибут. Я никогда о нем не задумывался пока мне не написал незрячий человек. Пришлось несколько дней отлаживать всю программу, что бы такие люди могли ей пользоваться. Обычно используют TalkBack. Еще такой момент, есть текст в виде html, так вот для зрячих его видно красиво, а вот TalkBack может начать читать тэги и прочую лабуду. Пришлось и в такие компоненты прописывать чистый текст.
What is android:contentDescription=»@string/desc» in ImageView’s xml?
I added an imageView in GraphicalLayout but it looks different on my real device than on AVD. I found that I need to add contentDescription in a layout .xml , but when I add: contentDescription=»@string/desc» there is an error:
«No resource found that matches the given name (at ‘contentDescription’ with value ‘@string/desc’)»
What is this string «desc»? What should it looks like?
asked Jul 21, 2012 at 21:05
8,801 7 7 gold badges 34 34 silver badges 33 33 bronze badges
6 Answers 6
It’s for the Accessibility Features of Android. The contentDescription is what get’s read back to the (assumingly blind or hard-of-sight user) so they have an idea of what the picture is since they aren’t able to view it.
As to answer your question, @iturki gives the start of it. You write the string to use for the description in strings.xml and give it a name of ‘desc’ or whatever your heart desires, then you set the value of contentDescription in the ImageView to @string/desc , either in the layout or programmatically. Like I said before, it’s to help users with poor eyesight get a general idea of what the image is portraying 🙂
answered Jul 21, 2012 at 21:12
starscream_disco_party starscream_disco_party
2,866 5 5 gold badges 26 26 silver badges 43 43 bronze badges
It’s not technically an error, it’s a warning saying that the Accessibility isn’t as good as it could be. Adding a string to contentDescription just gives TalkBack , or whichever Accessibility app the user has, content to read back to describe the image, since it’s not physically viewable by the impaired user.
Jul 21, 2012 at 21:27
And for purely decorative images, you can set android:contentDescription=»@null» to no content description.
Стилизация Android-приложений и дизайн-система: как это сделать и подружить одно с другим

В какой-то момент любое крупное приложение разрастается так, что сложно везде поддерживать однотипный дизайн и динамично реагировать на любые изменения и тенденции в дизайне и UX-требованиях.
Поэтому решили внедрить в наше приложение дизайн-систему и добавить поддержку нескольких тем оформления.
Изучив различные способы, выработали свой подход к решению такой задачи. Хотелось сделать так, чтобы дизайн-систему и поддержку стилей можно было повторно использовать в других своих проектах. В соответствии с этой идеей разрабатывались компоненты и темы.
Компоненты дизайн-системы
Дизайн-система и её компоненты предназначены для унификации дизайна и стилевого единства во всем приложении.
Компонентами дизайн-системы в нашем случае будем называть custom view с возможностью адаптации к нескольким стилям приложения. Компоненты могут применяться в любом месте приложения (кнопки, элементы списка, заголовки и т.д.).
Проектирование, отладка и доработка компонентов дизайн-системы
Заказчиками компонентов дизайн-системы являются дизайнеры. С ними на первом этапе согласовываем надобность элемента (оценка переиспользуемости) и его функциональность.
После согласования должно быть понятно, какие опции нужно вынести в атрибуты custom view (цвет текста, текст, иконочку, цвет тинта иконочки и т.д.), а какие скрыть от изменений извне (это позволяет уберечь элемент от неправильного использования разработчиками).
Далее дизайнеры отрисовывают компонент в своих средах и отдают на разработку.
При реализации компонента нужно добавить поддержку тем (светлая или темная тема и т.д.) О том, как компонент поддерживает несколько тем, я расскажу ниже.
Лучшие методики
- Создать модуль с компонентами дизайн-системы. Из положительных моментов: отдельный модуль может быть использован в других приложениях, а модульность позволяет быстрее ориентироваться.
- Создать тестовое приложение с компонентами дизайн-системы. Это ускоряет разработку и отладку.
Способы внедрения темы в приложение
Мне известно два способа поддержки стилей в Android:
- Программный (программная перекраска).
- Стандартные механизмы стилей в Android.
Программный способ
Мы перекрашиваем всю иерархию view в runtime. Рекурсивно проходимся по ней и по определенным правилам перехода из одной темы в другую перекрашиваем компоненты. Те из них, которые не должны перекрашиваться, маркируются с помощью android:tag или android:contentDescription . Эти компоненты не учитываются при разборе иерархии экрана.
Перекрашивать можно как перед отображением экрана (например, в onStart() у Activity ), так и при работе с ним.
Недостатки
- Требует дополнительных ресурсов, снижает производительность. Стилизация применяется после инициализации всех компонентов.
- Нужно быть внимательным к правилам перехода из одной темы в другую. Требуется учесть огромное множество правил перекраски, можно что-то забыть. Получается длинная простыня из switch — case (Java) или when (Kotlin). И в довесок требуется учесть элементы, которые не нужно красить при помощи вышеупомянутых тегов.
- Нельзя частично перекрасить в соответствии с темами. В любом правиле есть исключения, и не всегда всё в приложении делается по дизайн-системе. Непонятно, как действовать если требуется частичная перекраска некоторых элементов.
if (view is TextView) < view.setTextColor( if (darkMode) R.color.blue else R.color.black ) >else if (view is TabLayout)
Достоинства
Не требует пересоздания Activity (это важно! Нет морганий при смене темы).
Я внедрил этот подход в одном известном всем продукте (см. скриншоты). Работает довольно быстро при простой однотипной вёрстке(в данном случае она была простая).



Стандартный механизм стилей в Android
Стиль — локальная стилизация экрана или view, затрагивающая только отдельный экран или view. Часто такую стилизацию называют «ThemeOverlay», или «легковесная» тема, которая позволяет переопределить атрибуты основной темы).
Тема — глобальная стилизация экранов приложения, затрагивающая подмену стилей, цветов и т.д. у всего, что мы видим на экранах приложения.
Темой можно считать множество стилизаций, которые можно переключать.
Примеры
В теме могут содержаться как стили конкретных view элементов, так и конкретные цвета.
Здесь объявлен стиль для конкретной view:
Стили поддерживают явное и неявное наследование:
- Явное: Header1 унаследован от BaseTextWidget .
- Неявное: Header1.Light унаследован от Header1 .
Если к текстовому элементу мы применим стиль Header1.Light / Dark , то подтянутся стили Header1.Light / Dark и Header1 (достоинство неявного наследования)
Множественного наследования темы не поддерживают. Вероятно, из-за конфликтов одноименных атрибутов.
Стили каждого компонента дизайн-системы мы решили размещать в файлах attrs_component_name.xml (см. attrs_header1 , attrs_button и т.д.)
Стилизация компонентов дизайн системы. Архитектура компонентов. Поддержка нескольких тем
Стандартный конструктор view
Стандартный конструктор view предоставляет обширные средства для настройки элемента. Внешний вид элементов можно изменить через .xml-атрибуты или через определение стиля по умолчанию в стандартном конcтрукторе view.
Рассмотрим стандартный конструктор view на примере H1Component (задаёт крупный текст в шапке экранов):
class H1Component @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.cm_header1_style ) : AppCompatTextView(context, attrs, defStyleAttr)
Здесь attrs — атрибуты из определения .xml (в том числе кастомные атрибуты view). Они парсятся и применяются стандартным образом (см. ниже на примере FabComponent ).
class FabButtonComponent @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageButton(context, attrs, defStyleAttr) < init < val a = context.obtainStyledAttributes( attrs, R.styleable.FabButtonComponent ) val icon = a.getDrawable(R.styleable.FabButtonComponent_cm_icon) a.recycle() // apply attrs here >>
defStyleAttr — стиль view по умолчанию.
context — контекст view, при помощи которого она создана.
ВАЖНО: чтобы view успешно переключала тему, необходимо чтобы она была создана при помощи контекста, унаследованного от android.view.ContextThemeWrapper (то есть контекст activity подходит, а applicationContext — не подходит (применится тема, которая подтянется из стиля, указанного в Manifest экрана).
ВАЖНО: при такой реализации главный приоритет у атрибутов, объявленных в .xml. У стилей, описанных в теме, приоритет ниже.
Интеграция стиля в компоненты дизайн системы и его связь с темой
Для поддержки темы компонентами дизайн-системы мы определяем в компонентах defStyleAttr и переключаем его в соответствии с темой, в которой он определен.
Реализация темы в приложении
Создаем две темы:
Компоненты дизайн системы системы будут тянуть этот стиль в таком ключе:
class MyBestText @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = R.attr.best_textview_style ) : TextView(context, attrs, defStyleAttr)
Тут определены стили каждой темы для этого элемента:
Применяем тему через стандартный механизм Android.
При создании Activity указываем нужную тему. Тогда MyBestText подтянет нужный стиль и окрасит свой текст в белый или черный в зависимости от темы (см. выше описание темы MyBestText ).
private void setAppTheme(@NonNull Boolean isDarkModeEnabled) < if (isDarkModeEnabled) < setTheme(R.style.DesignSystemDark); >else
Цвета из темы мы будем разрешать прямо из .xml и подтягивать из темы.
ВАЖНО: начиная с Android 5.0 допускается отовсюду динамически разрешать android:background=»?attr/primary_background» (селекторы, shape, vector drawables и т.д.) В Android 4.4 есть ограничение на селекторы, при попытке динамически разрешить итоговый цвет из селекторов система упадёт.
При всех достоинствах такой реализации компоненты дизайн-системы не могут в preview Android Studio полноценно работать со стилизованными темами (к элементам не будут применяться стили).
Пока тема официально не использована нашими экранами, а только подключается программно (то есть стили наших activity не подгружают явным образом тему из Manifest ), мы не можем комфортно работать с элементами, поддерживающими темы в preview (их даже не будет в списке).
Тестирование компонентов дизайн-системы
Для тестирования и анализа степени покрытия приложения дизайнеры предложили разработать отладочную панель с настройками стилей компонентов, цветов и т.д.

Темы в Android являются неизменяемыми, но их всегда можно перезаписать полностью или частично через Activity.setTheme ( @StyleRes final int resid ). Так можно в нужный момент получить любую комбинацию стилей и собрать свою собственную тему. Но все стили должны быть объявлены в .xml заранее.
Программно изменять атрибут темы без отсылок к объявленным стилям, к сожалению, нельзя. По крайней мере, я не нашёл способа.
Если знаете, как подсунуть свой цвет в атрибут темы (не объявленный в ресурсах как style ), то напишите мне. Тогда мы сможем прямо из коробки манипулировать цветами с бэка на уровне стилизации всего приложения!
Делаем рабочее preview компонентов дизайн-системы в Android Studio
Темы экранов приложения должны наследоваться от темы дизайн-системы.
Preview компонентов в .xml
При некорректно установленной теме экрана компоненты дизайн-системы тоже не будут отображаться корректно (не применятся стили и цвета):

При установке темы, унаследованной от темы дизайн-системы, мы получим вот что:

Видно, как разрешились все атрибуты темы и правильно подтянулись стили компонента.
Проверка поведения компонентов в другой теме в Preview без пересборки приложения
Чтобы проверить отображение в другой теме достаточно переключить тему в Preview light/dark.
Если конкретные реализации темы завязаны на ресурсы values/values-night, то можно переключать из preview в dark mode. И всё будет работать из коробки без выставления setTheme в Activity .

Переключение тем в приложении
Переключение тем в приложении может быть завязано на системное переключение dark-mode. В таком случае темы должны быть определены в директориях values и values-night.
Если планируется три и более тем, то потребуется вручную разрешать, какую из тем поставить через activity.setTheme() .
Результаты стилизации смотрим ниже:






А как же третья тема под AB-тестом?
Как ранее говорилось, в таком случае придется вручную выставлять setTheme для применения нужной темы.
Итоги
-
У нас есть надежный механизм динамической смены тем и подстройки стилей (как в отладочной панели).