Стили и темы

Попробуйте Compose
Jetpack Compose – это рекомендуемый набор инструментов для создания пользовательского интерфейса в Android. Узнайте, как работать с темами в Compose.

Стили и темы в Android позволяют отделить детали дизайна приложения от структуры и поведения пользовательского интерфейса, подобно таблицам стилей в веб-дизайне.

Стиль – это набор атрибутов, определяющих внешний вид одного элемента View. Стиль может определять такие атрибуты, как цвет шрифта, размер шрифта, цвет фона и многое другое.

Тема – это набор атрибутов, которые применяются ко всему приложению, действию или иерархии View, а не только к отдельному объекту View. Когда вы применяете тему, каждое представление в приложении или действии применяет каждый из поддерживаемых атрибутов темы. Темы также могут применять стили к элементам, не относящимся к представлению, например к строке состояния и фону окна.

Стили и темы объявляются в файле ресурсов стилей в res/values/, который обычно называется styles.xml.

Рисунок 1. Две темы, примененные к одному и тому же действию: Theme.AppCompat (слева) и Theme.AppCompat.Light (справа).

Темы и стили

Темы и стили во многом похожи, но используются для разных целей. Темы и стили имеют одинаковую базовую структуру – пару "ключ-значение", которая сопоставляет атрибуты с ресурсами.

Стиль определяет атрибуты для определенного типа представления. Например, один стиль может определять атрибуты кнопки. Каждый атрибут, который вы указываете в стиле, можно задать в файле макета. Извлечение всех атрибутов в стиль упрощает их использование и поддержку в нескольких виджетах.

Тема определяет набор именованных ресурсов, на которые могут ссылаться стили, макеты, виджеты и т. д. Темы присваивают семантические названия, например colorPrimary, ресурсам Android.

Стили и темы предназначены для совместной работы. Например, в стиле может быть указано, что одна часть кнопки имеет цвет colorPrimary, а другая – colorSecondary. Определения этих цветов задаются в теме. Когда устройство переходит в ночной режим, приложение может переключиться со светлой темы на тёмную, изменив значения для всех этих названий ресурсов. Вам не нужно менять стили, поскольку в них используются семантические названия, а не конкретные определения цветов.

Дополнительную информацию о том, как темы и стили работают вместе, можно найти в записи блога Android styling: themes vs styles.

Как создать и применить стиль

Чтобы создать стиль, откройте файл res/values/styles.xml проекта. Для каждого стиля, который вы хотите создать, выполните следующие действия:

  1. Добавьте элемент <style> с уникальным названием стиля.
  2. Добавьте элемент <item> для каждого атрибута стиля, который вы хотите определить. name в каждом элементе указывает атрибут, который вы используете в качестве атрибута XML в макете. Значение в элементе <item> – это значение атрибута.

Например, вы задали следующий стиль:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="GreenText" parent="TextAppearance.AppCompat">
        <item name="android:textColor">#00FF00</item>
    </style>
</resources>

Применить стиль к представлению можно следующим образом:

<TextView
    style="@style/GreenText"
    ... />

Каждый атрибут, указанный в стиле, применяется к этому представлению, если представление его принимает. Представление игнорирует все атрибуты, которые не принимает.

Однако вместо того, чтобы применять стиль к отдельным представлениям, обычно стили применяются в качестве темы для всего приложения, действия или коллекции представлений, как описано в другом разделе этого руководства.

Как расширить и настроить стиль

При создании собственных стилей всегда расширяйте существующий стиль из фреймворка или библиотеки поддержки, чтобы сохранить совместимость со стилями пользовательского интерфейса платформы. Чтобы расширить стиль, укажите его в атрибуте parent. Затем вы можете переопределить унаследованные атрибуты стиля и добавить новые.

Например, вы можете унаследовать внешний вид текста по умолчанию для платформы Android и изменить его следующим образом:

<style name="GreenText" parent="@android:style/TextAppearance">
    <item name="android:textColor">#00FF00</item>
</style>

Однако основные стили приложения всегда должны наследоваться из библиотеки поддержки Android. Стили в библиотеке поддержки обеспечивают совместимость за счет оптимизации каждого стиля для атрибутов пользовательского интерфейса, доступных в каждой версии. Названия стилей из библиотеки поддержки часто похожи на названия стилей платформы, но содержат AppCompat.

Чтобы унаследовать стили из библиотеки или собственного проекта, укажите название родительского стиля без части @android:style/, показанной в примере выше. Например, в следующем примере стили внешнего вида текста наследуются из библиотеки поддержки:

<style name="GreenText" parent="TextAppearance.AppCompat">
    <item name="android:textColor">#00FF00</item>
</style>

Вы также можете наследовать стили (кроме стилей платформы), расширив название стиля с помощью точечной нотации вместо атрибута parent. Для этого добавьте к названию стиля название стиля, который вы хотите унаследовать, разделив их точкой. Обычно это делается только при расширении собственных стилей, а не стилей из других библиотек. Например, следующий стиль наследует все стили от GreenText в предыдущем примере, а затем увеличивает размер текста:

<style name="GreenText.Large">
    <item name="android:textSize">22dp</item>
</style>

Вы можете наследовать стили таким образом сколько угодно раз, добавляя в цепочку новые названия.

Чтобы узнать, какие атрибуты можно объявить с помощью тега <item>, обратитесь к таблице "XML-атрибуты" в справочных материалах по различным классам. Все представления поддерживают XML-атрибуты из базового класса View, а многие представления добавляют свои собственные специальные атрибуты. Например, XML-атрибуты TextView включают атрибут android:inputType, который можно применить к текстовому представлению, получающему входные данные, например к виджету EditText.

Как применить стиль в качестве темы

Тема создается так же, как и стиль. Разница заключается в том, как вы его применяете: вместо применения стиля с атрибутом style в представлении вы применяете тему с атрибутом android:theme в теге <application> или теге <activity> в файле AndroidManifest.xml.

Например, вот как можно применить темную тему Material Design из библиотеки поддержки Android ко всему приложению:

<manifest ... >
    <application android:theme="@style/Theme.AppCompat" ... >
    </application>
</manifest>

А вот как применить светлую тему только к одному действию:

<manifest ... >
    <application ... >
        <activity android:theme="@style/Theme.AppCompat.Light" ... >
        </activity>
    </application>
</manifest>

Каждое представление в приложении или действии применяет поддерживаемые стили из тех, которые определены в заданной теме. Если представление поддерживает только некоторые атрибуты, объявленные в стиле, то оно применяет только эти атрибуты и игнорирует те, которые не поддерживает.

Начиная с Android 5.0 (уровень API 21) и библиотеки поддержки Android версии 22.1, вы также можете указать атрибут android:theme для представления в файле макета. Это изменяет тему для этого представления и любых дочерних представлений, что полезно для изменения цветовых палитр темы в определенной части вашего интерфейса.

В предыдущих примерах показано, как применить тему, например Theme.AppCompat, которая поставляется с библиотекой поддержки Android. Однако обычно тему настраивают в соответствии с брендом приложения. Лучший способ сделать это – расширить эти стили из библиотеки поддержки и переопределить некоторые атрибуты, как описано в следующем разделе.

Иерархия стилей

Android предоставляет множество способов задать атрибуты в приложении для Android. Например, вы можете задать атрибуты непосредственно в макете, применить стиль к представлению, применить тему к макету и даже задать атрибуты программно.

При выборе стиля приложения учитывайте иерархию стилей Android. Для единообразия рекомендуется использовать темы и стили. Если вы укажете одни и те же атрибуты в нескольких местах, то будут применены атрибуты, указанные в списке ниже. Список упорядочен по приоритету (от высокого к низкому).

  1. Применение стилей на уровне символов или абзацев с помощью текстовых фрагментов к классам, производным от TextView.
  2. Применение атрибутов программным способом.
  3. Применение отдельных атрибутов непосредственно к представлению.
  4. Применение стиля к представлению.
  5. Стиль по умолчанию.
  6. Применение темы к набору представлений, действию или всему приложению.
  7. Применение определенных стилей, например настройка TextAppearance для TextView.

Рисунок 2. Стиль, заданный в span, переопределяет стиль, заданный в textAppearance.

TextAppearance

Одно из ограничений стилей заключается в том, что к объекту View можно применить только один стиль. Однако в TextView вы также можете указать атрибут TextAppearance, который работает аналогично стилю, как показано в следующем примере:

<TextView
    ...
    android:textAppearance="@android:style/TextAppearance.Material.Headline"
    android:text="This text is styled via textAppearance!" />

TextAppearance позволяет задать стиль текста, а View – стиль других элементов. Однако обратите внимание, что если вы определяете какие-либо текстовые атрибуты непосредственно в View или в стиле, эти значения переопределяют значения TextAppearance.

TextAppearance поддерживает подмножество атрибутов стилей, которые предлагает TextView. Полный список атрибутов приведен в статье TextAppearance.

Некоторые распространенные атрибуты TextView, которые не включены: lineHeight[Multiplier|Extra], lines, breakStrategy и hyphenationFrequency. TextAppearance работает на уровне символов, а не абзацев, поэтому атрибуты, влияющие на весь макет, не поддерживаются.

Как настроить тему по умолчанию

Когда вы создаете проект в Android Studio, к вашему приложению по умолчанию применяется тема Material Design, как определено в файле styles.xml проекта. Этот стиль AppTheme расширяет тему из библиотеки поддержки и включает переопределения для атрибутов цвета, которые используются ключевыми элементами пользовательского интерфейса, такими как панель приложения и плавающая кнопка действия (если используется). Таким образом, вы можете быстро настроить цветовое оформление вашего приложения, обновив предоставленные цвета.

Например, ваш файл styles.xml выглядит следующим образом:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

Значения стилей – это ссылки на другие ресурсы цвета, определенные в файле res/values/colors.xml проекта. Это файл, который вы редактируете, чтобы изменить цвета. Чтобы улучшить взаимодействие с пользователем, добавьте динамические и дополнительные пользовательские цвета. Подробнее об этом рассказывается в обзоре цветов Material Design.

Когда вы определитесь с цветами, обновите значения в res/values/colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--   Color for the app bar and other primary UI elements. -->
    <color name="colorPrimary">#3F51B5</color>

    <!--   A darker variant of the primary color, used for
           the status bar (on Android 5.0+) and contextual app bars. -->
    <color name="colorPrimaryDark">#303F9F</color>

    <!--   a secondary color for controls like checkboxes and text fields. -->
    <color name="colorAccent">#FF4081</color>
</resources>

Затем вы можете переопределить любые другие стили. Например, вы можете изменить цвет фона активности следующим образом:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    ...
    <item name="android:windowBackground">@color/activityBackground</item>
</style>

Список атрибутов, которые можно использовать в теме, приведен в таблице атрибутов на странице R.styleable.Theme. При добавлении стилей для представлений в макете вы также можете найти атрибуты в таблице "XML-атрибуты" в справочнике по классам представлений. Например, все представления поддерживают XML-атрибуты из базового класса View.

Большинство атрибутов применяется к определенным типам просмотров, а некоторые – ко всем. Однако некоторые атрибуты темы, перечисленные на странице R.styleable.Theme, применяются к окну действия, а не к представлениям в макете. Например, windowBackground изменяет фон окна, а windowEnterTransition определяет анимацию перехода, которая будет использоваться при запуске действия. Подробнее о том, как запустить действие с помощью анимации…

Библиотека поддержки Android также предоставляет другие атрибуты, которые можно использовать для настройки темы, расширенной из Theme.AppCompat, например атрибут colorPrimary, показанный в предыдущем примере. Их лучше всего просматривать в файле attrs.xml библиотеки.

В библиотеке поддержки также доступны другие темы, которые можно расширить вместо показанных в предыдущем примере. Посмотреть доступные темы можно в файле themes.xml библиотеки.

Добавьте стили для определенных версий

Если в новой версии Android добавлены атрибуты темы, которые вы хотите использовать, вы можете добавить их в свою тему, сохранив совместимость со старыми версиями. Вам понадобится ещё один файл styles.xml, сохраненный в каталоге values, который содержит модификатор версии ресурса:

res/values/styles.xml        # themes for all versions
res/values-v21/styles.xml    # themes for API level 21+ only

Поскольку стили в файле values/styles.xml доступны для всех версий, ваши темы в values-v21/styles.xml могут наследовать их. Это означает, что вы можете избежать дублирования стилей, начав с "базовой" темы, а затем расширив ее в стилях для конкретной версии.

Например, чтобы объявить переходы между окнами для Android 5.0 (уровень API 21) и более поздних версий, необходимо использовать новые атрибуты. Базовая тема в res/values/styles.xml может выглядеть так:

<resources>
    <!-- Base set of styles that apply to all versions. -->
    <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/primaryColor</item>
        <item name="colorPrimaryDark">@color/primaryTextColor</item>
        <item name="colorAccent">@color/secondaryColor</item>
    </style>

    <!-- Declare the theme name that's actually applied in the manifest file. -->
    <style name="AppTheme" parent="BaseAppTheme" />
</resources>

Затем добавьте стили для конкретной версии в res/values-v21/styles.xml, как показано ниже:

<resources>
    <!-- extend the base theme to add styles available only with API level 21+ -->
    <style name="AppTheme" parent="BaseAppTheme">
        <item name="android:windowActivityTransitions">true</item>
        <item name="android:windowEnterTransition">@android:transition/slide_right</item>
        <item name="android:windowExitTransition">@android:transition/slide_left</item>
    </style>
</resources>

Теперь вы можете применить AppTheme в файле манифеста, и система выберет стили, доступные для каждой версии системы.

Подробнее о том, как использовать альтернативные ресурсы для разных устройств…

Как настроить стили виджета

У каждого виджета в фреймворке и библиотеке поддержки есть стиль по умолчанию. Например, если вы оформляете приложение с помощью темы из библиотеки поддержки, экземпляр Button оформляется с помощью стиля Widget.AppCompat.Button. Если вы хотите применить к кнопке другой стиль виджета, используйте атрибут style в файле макета. Например, в следующем фрагменте кода применяется стиль кнопки без границ:

<Button
    style="@style/Widget.AppCompat.Button.Borderless"
    ... />

Если вы хотите применить этот стиль ко всем кнопкам, вы можете объявить его в файле buttonStyle вашей темы следующим образом:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item>
    ...
</style>

Вы также можете расширить стили виджетов, как и любые другие стили, а затем применить собственный стиль виджета в макете или теме.

Дополнительные ресурсы

Чтобы узнать больше о темах и стилях, ознакомьтесь со следующими дополнительными ресурсами:

Записи в блоге