Stylish Apps

Theme
Глобальное множество атрибутов
Style
Локальная группа атрибутов
Theme Overlay
"фильтр", переопределяющий часть темы

Styles

Styles

Позволяет определить внешний вид View

<TextView style="@style/header"/>
<TextView style="@style/regular"/>

И избежать дублирование кода

Выносите стили!

Q: Как раскрасить кнопку?

Параметры AppCompat


?style
?style
                

значения по-умолчанию

  • Widget.AppCompat.Button
  • Widget.AppCompat.Button.Borderless

Widget.AppCompat.Button


Base.Widget.AppCompat.Button

Widget.Material.Button

background: @drawable/btn_default_material

<ripple android:color="?attr/colorControlHighlight">
  <item>
    <nine-patch
            android:src="@drawable/btn_mtrl_alpha"
            android:tint="?attr/colorButtonNormal">
    </nine-patch>
  </item>
</ripple>
                

Стили можно наследовать

Style heritage


<style name="Implicit">
    <item name="android:textSize">60dp</item>
</style>
<style name="Explicit">
    <item name="android:textColor">@color/red</item>
</style>

<style name="Implicit.LargeTransparent">
    <item name="android:alpha">0.5</item>
</style>
<style name="Implicit.LargeTransparentRed" parent="Explicit">
    <item name="android:alpha">0.5</item>
</style>
                

LargeTransparent

LargeTransparentRed

TransparentRed

ссылки

?attr/resourceName

?android:attr/resourceName

При написании приложения мы должны всегда использовать ссылки ?attr/resource, а не прямые указания @color/black
Стили, селекторы и другие drawable должны ссылаться на атрибуты темы
Q: Как раскрасить кнопку?
A: Изменить атрибут colorButtonNormal в теме приложения

colorButtonNormal - это селектор

AppCompat

Основные атрибуты - фон

android:windowLightStatusBar
Цвет иконок (светлый/темный)
android:windowBackground
Фон главного окна
android:colorBackground
Фон всего (алерты, активити)
android:colorForeground
?? противоположный цвет ??

Основные атрибуты - фон

Основные атрибуты - текст

android:textColorPrimary
android:textColorPrimaryInverse
Цвет заголовка colorPrimary по-умолчанию
android:textColorSecondary
android:textColorSecondaryInverse
Цвет обычного текста - Ч/Б по-умолчанию
android:textColorTertiary
android:textColorTertiaryInverse
Цвет хинтов - светло-темно серый
textColorError
Цвет ошибки - красный

Основные компоненты - селекторы

android:textColor
read only
android:editTextColor
editable
android:textColorHint
подсказки
android:textColorLink
ссылки

редкие

android:textColorHighlight
фон выделенного текста
android:textColorPrimaryDisableOnly
фон Off Switch кнопки

Основные компоненты - disabled

android:disabledAlpha
[0; 1] прозрачность

Основные атрибуты - стили

android:toolbarStyle
ThemeOverlay для тулбара
android:dropDownListViewStyle
Выпадающий список
android:buttonStyle
Кнопка
android:borderlessButtonStyle
Кнопка-ссылка

Их еще много...

Основные атрибуты - цвета

colorPrimary
Цвет заголовков
colorPrimaryDark
Фон status bar
colorAccent
Цвет интерактивных элементов*

colorAccent

Зависимые по-умолчанию от colorAccent

colorControlNormal
Off
colorControlActivated
On
colorControlHighlight
Подсветка при нажатии (ripple!)

На самом деле colorControlHighlight не зависит от accent - это прозрачный черный #1f000000, поэтому его не видно на черных элементах

colorAccent

N, A, H N, A, H N, A, H

colorAccent - проблемы

N, A, H

ThemeOverlay.AppCompat


<style name="AppThemeOverlay.Colorful" parent="ThemeOverlay.AppCompat">
    <item name="colorControlNormal">?colorAccent</item>
</style>

<style name="AppThemeOverlay.Desaturated" parent="ThemeOverlay.AppCompat">
    <item name="colorControlActivated">?android:textColorTertiary<item>
</style>
                

Q: Как это работает?


Посмотрим как работает View

View - Inflate

  1. LayoutInflater складывает стиль в AttributeSet
  2. значения AttributeSet извлекаются через контекст


Context - хранитель тем!

ContextThemeWrapper
extends ContextWrapper extends Context

Обратно по дереву собираются темы

  1. View
  2. Layout
  3. Layout
  4. Activity

Theme(in)ception

LightTheme
ToolbarDarkTheme
ToolbarPopupLightTheme
Тему лучше всего назначать на глобальные сущности - Application, Activity, Fragment
Overlay подходит для ViewGroup - Toolbar, AlertDialog, а возможно и для вашего блока с формой

<LinearLayout
        android:theme="@style/AppThemeOverlay.Colorful">
    
</LinearLayout>
                
Стили применяются для конечного элемента View, а их параметры резолвятся относительно темы

Возможны ситуации, когда на 1 вьюшке будет и тема и стиль

Как правило View резолвит значения 1 раз, в момент создания.

Чтобы изменить тему - необходимо пересоздать View.

у Activity можно позвать метод recreate()

attrs.xml

Позволяют добавлять собственные атрибуты

attrs.xml лучше подходят для семантики вашей предметной области, чем colors.xml

Именование ресурсов

colors.xml
@color/red,
@color/green_light,
@color/blue_dark
attrs.xml
?attr/colorPrimary,
?attr/colorAccent,
?attr/colorPremiumUser
color/ & drawable/ selectors
@color/ic_edit_selector,
@drawable/bg_button_primary,
@color/text_primary_selector

Кастомные атрибуты

attrs.xml


<declare-styleable name="Base.AppTheme">
    <attr name="colorPrimaryLight" format="color|reference" />
    <attr name="textColorDisabledDefault" format="color|reference" />

    <attr name="ohmyButtonColorNormal" format="color|reference"/>
    <attr name="ohmyButtonColorDisabled" format="color|reference" />
</declare-styleable>
                

Кастомные атрибуты

Дополнительные цвета

colorPrimaryLight
Инверсный PrimaryDark, почему-то его нет
textColorDisabledDefault
ohmyButtonColorNormal
ohmyButtonColorDisabled
Ожидамое поведение disabled

Make AppCompat great again

Готовые и предсказуемые Light/Dark темы

<style name="AppTheme.Light.Green">
    <item name="colorPrimaryLight">@color/green_light</item>
    <item name="colorPrimary">@color/green</item>
    <item name="colorPrimaryDark">@color/green_dark</item>
    <item name="colorAccent">@color/red_light</item>
    <item name="colorControlActivated">@color/red</item>
</style>

<style name="AppTheme.Dark.Green">
    <item name="colorPrimaryLight">@color/green_light</item>
    <item name="colorPrimary">@color/green</item>
    <item name="colorPrimaryDark">@color/green_dark</item>
    <item name="colorAccent">@color/red_light</item>
    <item name="colorControlActivated">@color/red</item>
</style>
                
Готовые и предсказуемые Light/Dark темы
Исходники в открытом доступе
Живая apk со сменой тем

Что внутри?

  • Базовые темы Dark/Light
  • Предсказуемый disabled
  • Набор селекторов на все случаи жизни
  • Фрагмент показывающий используемые цвета

Готовые ресурсы

Селекторы

Ripple