- Android styling: common theme attributes
- Android Styling: Themes vs Styles
- The Android styling system offers a powerful way to specify your app’s visual design, but it can be easy to misuse…
- Colors
- Dimens
- Drawables
- TextAppearances
- Shape
- Button Styles
- Floats
- App vs Android namespace
- More Resources
- Do It Yourself
- Question (mark) everything
- Основы темизации в Android
- Стиль по умолчанию
- Стиль и тема
- Наложение тем
- TextAppearance
- Заключение
Android styling: common theme attributes
In the previous article in this series on Android styling, we looked at the difference between themes and styles and how themes allow you to write more flexible styles and layouts which isolate changes:
Android Styling: Themes vs Styles
The Android styling system offers a powerful way to specify your app’s visual design, but it can be easy to misuse…
Specifically we recommended using theme attributes to provide a point of indirection to resources, so that you can vary them (e.g. in dark theme). That is, if you find yourself writing a direct resource reference (or worse yet, a hardcoded value 😱) in a layout or style, consider if you should use a theme attribute instead.
But what theme attributes are available to use? This post highlights the common ones that you should know about; those that come from Material, AppCompat or the platform. This is not a complete list (for that I’d recommend browsing the attrs files linked below where they are defined) but these are the attributes that I use all the time.
Colors
Many of these colors come from the Material color system, which defines semantic names for colors that you can use throughout your app (implemented as theme attrs).
- ?attr/colorPrimary The primary branding color for the app.
- ?attr/colorSecondary The secondary branding color for the app, usually a bright complement to the primary branding color.
- ?attr/colorOn[Primary, Secondary, Surface etc] A color which contrasts against the named color.
- ?attr/color[Primary, Secondary]Variant An alternate shade of the given color.
- ?attr/colorSurface A color for surfaces of components, such as cards, sheets, and menus.
- ?android:attr/colorBackground The background for the screen.
- ?attr/colorPrimarySurface switches between colorPrimary in the Light themes, colorSurface in the Dark theme.
- ?attr/colorError A color for displaying errors.
Other handy colors:
- ?attr/colorControlNormal The color applied to icons/controls in their normal state.
- ?attr/colorControlActivated The color applied to icons/controls in their activated state (e.g. checked).
- ?attr/colorControlHighlight The color applied to control highlights (e.g. ripples, list selectors).
- ?android:attr/textColorPrimary The most prominent text color.
- ?android:attr/textColorSecondary Secondary text color.
Dimens
- ?attr/listPreferredItemHeight Standard (min) height for list items.
- ?attr/actionBarSize The height of a toolbar.
Drawables
- ?attr/selectableItemBackground A ripple/highlight for interactive items (also handy for foregrounds!!)
- ?attr/selectableItemBackgroundBorderless An unbounded ripple.
- ?attr/dividerVertical A drawable that may be used as a vertical divider between visual elements.
- ?attr/dividerHorizontal A drawable that may be used as a horizontal divider between visual elements.
TextAppearances
Material defines a type scale — a discrete set of text styles that you should use throughout your app, each of which is provided as a theme attribute which can be set as a textAppearance . Check out the Material type scale generator to help generate a scale for different fonts.
- ?attr/textAppearanceHeadline1 defaults to light 96sp text.
- ?attr/textAppearanceHeadline2 defaults to light 60sp text.
- ?attr/textAppearanceHeadline3 defaults to regular 48sp text.
- ?attr/textAppearanceHeadline4 defaults to regular 34sp text.
- ?attr/textAppearanceHeadline5 defaults to regular 24sp text.
- ?attr/textAppearanceHeadline6 defaults to medium 20sp text.
- ?attr/textAppearanceSubtitle1 defaults to regular 16sp text.
- ?attr/textAppearanceSubtitle2 defaults to medium 14sp text.
- ?attr/textAppearanceBody1 defaults to regular 16sp text.
- ?attr/textAppearanceBody2 defaults to regular 14sp text.
- ?attr/textAppearanceCaption defaults to regular 12sp text.
- ?attr/textAppearanceButton defaults to medium all caps 14sp text.
- ?attr/textAppearanceOverline defaults to regular all caps 10sp text.
Shape
Material employs a shape system which is implemented as theme attrs for small, medium and large components. Note that if you’re setting a shape appearance on a custom component, you likely want to use a MaterialShapeDrawable as it’s background which understands and implements the shaping.
- ?attr/shapeAppearanceSmallComponent used for Buttons, Chips, Text Fields etc. Defaults to rounded 4dp corners.
- ?attr/shapeAppearanceMediumComponent used for Cards, Dialogs, Date Pickers etc. Defaults to rounded 4dp corners.
- ?attr/shapeAppearanceLargeComponent used for Bottom Sheets etc. Defaults to rounded 0dp corners (i.e. square!)
Button Styles
This might seem super specific, but Material defines three types of buttons: Contained, Text and Outlined. MDC offers theme attrs that you can use to set the style of a MaterialButton :
- ?attr/materialButtonStyle defaults to contained (or just omit the style).
- ?attr/borderlessButtonStyle for a text style button.
- ?attr/materialButtonOutlinedStyle for outlined style.
Floats
- ?android:attr/disabledAlpha Default disabled alpha for widgets.
- ?android:attr/primaryContentAlpha The alpha applied to the foreground elements.
- ?android:attr/secondaryContentAlpha The alpha applied to secondary elements.
App vs Android namespace
You might have noticed that some attributes are referenced by
? android:attr/foo and others just by ?attr/bar . This is because some are defined by the Android platform, and as such you need the android part to reference them by their namespace (just like with view attributes in layouts: android:id ). Those without come from static libraries (i.e. AppCompat or MDC) which are compiled into your application, so don’t need the namespace (similar to how you might use app:baz in a layout). Some elements are defined both in the platform and in a library e.g. colorPrimary . In these cases, prefer the non-platform version, as this can be used on all API levels i.e. they’re duplicated in a library precisely to backport them. In these cases, I’ve listed the non-platform versions above.
prefer non-platform attributes which can be used on all API levels
More Resources
For a complete list of the theme attributes available to use, go to the source of truth:
Material Design Components:
Do It Yourself
Sometimes there isn’t a theme attribute which abstracts something you’d like to vary by theme. No worries… create your own! Here’s an example from the Google I/O app which shows a list of conference sessions in two screens.
They’re largely similar but the left screen must leave space for the sticky time headers while the right screen does not. We implemented this by abstracting where to align items behind a theme attribute so that we can vary them by theme and use the same layout across two different screens:
1. Define the theme attribute in attrs.xml
2. Provide different values in different themes:
3. Use the theme attr in the single layout used on both screens (each using one of the above themes):
Question (mark) everything
Knowing what theme attributes are available, equips you to use them when writing your layouts, styles or drawables. Using theme attributes makes it much easier to support theming (like dark theme) and to write more flexible, maintainable code. For a deep dive on this, join us in our next post in this series:
Источник
Основы темизации в Android
Темизация приложения может быть одним из самых запутанных вопросов в разработке Android. В то время как проект постоянно увеличивается, становится все труднее поддерживать стили компонентов и тематическое оформление приложения. Если у вас нет хорошей системы дизайна, то можно получить противоречивое оформление и несоответствующие цвета в приложении. Хорошее понимание стилизации и темизации поможет вам создать единообразный пользовательский интерфейс во всем приложении. Кроме того, если вы думаете о миграции на Compose, плохая система дизайна может создать дополнительные сложности.
Хорошая система дизайна требует правильной настройки стилизации и темизации. Это способствует созданию единообразных и многократно используемых стилей для наших компонентов. Но как на самом деле создать правильную систему стилей и тем?
На этот вопрос нет однозначного ответа, его можно разделить на 5 частей.
Стиль по умолчанию
Стиль в сравнении с темой
Атрибуты
Все начинается с атрибута. Без атрибутов в XML не было бы никаких характеристик, которые бы мы могли определить. Атрибуты — это именованные значения, которые имеют свое определение в файле attrs.xml . Атрибут может быть определен как для представления, так и для темы. Например, атрибут android:layout_width является атрибутом представления, а colorPrimary — атрибутом темы.
Атрибут представления устанавливается в XML представления либо путем установки непосредственно в теге, либо косвенно с помощью style (будет упомянуто позже).. Давайте рассмотрим, как мы можем установить красный фон кнопки с помощью атрибута представления android:backgroundTint .
Примечание: Для доступа к встроенным атрибутам используется префикс android.
Допустим, вы хотите изменить его фон на белый. Вы можете сделать это, установив атрибут android:backgroundTint на белый.
Это хорошо, если вы измените только одну кнопку. Но как быть, если вы хотите изменить все красные кнопки на белые? Этого можно добиться:
Использование атрибута темы для android:backgroundTint
Создание и применение стиля ко всем кнопкам
Атрибут темы — это атрибут, который не принадлежит ни одному представлению и может быть изменен на уровне темы.
Чтобы использовать атрибут темы для android:backgroundTint , давайте сначала определим пользовательский атрибут темы под названием myButtonBackground в attrs.xml .
Добавление пользовательского атрибута темы:
Тип атрибута задается с помощью поля format . Формат может быть задан как одиночный или множественный тип, например,
android:background format=»reference|color» , который принимает как ссылки на drawable-ресурс («reference»), так и цвет («color»).
Теперь вы можете использовать атрибут myButtonBackground для установки фона вашей кнопки. Но перед этим необходимо задать значение myButtonBackground . Оно должно быть определено либо в теме, либо в наложении темы, которое будет использоваться.
Установка значения атрибута темы:
Затем вы можете использовать этот атрибут для установки фона ваших кнопок.
Установка фона кнопки с помощью пользовательского атрибута:
Если вы измените значение атрибута, то изменится фон всех кнопок, использующих атрибут ?attr/myButtonBackground в качестве фона. В качестве альтернативы можно использовать ?myButtonBackground как сокращение вместо ?attr/myButtonBackground .
Но установка android:backgroundTint на myButtonBackground для всех кнопок может оказаться непосильной задачей. Чтобы решить эту проблему, мы создадим стиль и применим его ко всем кнопкам, используя стиль по умолчанию.
Стиль по умолчанию
Замечали ли вы, что если не задаете кнопке никакого фона, то все равно получаете фоновый drawable (выводимый средствами графических ресурсов объект)? Это происходит потому, что компонент Button (кнопка) имеет стиль по умолчанию, как и любой другой вид. Стиль по умолчанию используется в качестве базового стиля представления.
Давайте проверим стиль кнопки по умолчанию.
Стиль кнопки по умолчанию устанавливается с помощью атрибута темы R.attr.buttonStyle . Это означает, что вы можете изменить стиль по умолчанию всех кнопок в вашем приложении с помощью этого атрибута.
Давайте изменим стиль кнопки по умолчанию в нашей теме так, чтобы фон был красным.
Установка стиля кнопки по умолчанию с помощью атрибута buttonStyle :
Тогда при создании кнопки вы будете получать следующее.
Кнопка с красным фоном
Разве это не напоминает текст с красным фоном? Так происходит потому, что стиль MyButton не наследуется ни от каких стилей. По этой причине все кнопки будут содержать атрибут фонового изображения только в своем стиле по умолчанию. Давайте проверим, как стиль кнопки по умолчанию выглядит в AppCompat .
Стиль кнопок по умолчанию в AppCompat :
Как вы видите, эти атрибуты являются базовым стилем для кнопки. Давайте укажем Widget.AppCompat.Button в качестве родителя стиля MyButton и изменим атрибут background на backgroundTint , поскольку мы хотим изменить только цвет, а не drawable-объект.
Установка родительского стиля кнопки MyButton :
Затем мы получаем кнопку с красным фоном.
Кнопка с красным фоном
Стиль и тема
Мы уже упоминали о стиле и теме, но в чем разница между ними? И стиль, и тема — это набор атрибутов, но разница заключается в том, в каком случае они применяются. Стили предназначены для применения к представлениям, а темы — к действиям или всему приложению. По этой причине стиль должен содержать только атрибуты представления, а тема — только атрибуты темы.
Вы можете изменить стиль представления тремя способами:
Изменение атрибута представления в файле макета
Создание нового стиля и применение его с помощью атрибута представления style в файле макета
Указание стиля по умолчанию
Давайте посмотрим, как можно изменить фон кнопки в файле макета.
Изменение фона кнопки в файле макета:
Теперь давайте проверим, как мы можем создать стиль и применить его к этой кнопке.
Стиль кнопки с пользовательским фоновым drawable:
Установка пользовательского стиля для кнопки:
При применении стиля учитываются только атрибуты представления. Если вы попытаетесь установить любой атрибут темы внутри стиля MyButton , это не сработает. Для наглядности приведем пример:
Использовать атрибут темы colorPrimary внутри drawable фона кнопки.
Изменим значение colorPrimary внутри стиля MyButton
Фоновый drawable, который использует атрибут colorPrimary :
Изменение атрибута темы colorPrimary внутри стиля кнопки:
Тогда, несмотря на то, что мы установили основной цвет как красный, мы получим кнопку с фиолетовым фоном.
Кнопка с фиолетовым фоном
Это происходит потому, что представление знает только о своих собственных атрибутах; Кнопка (Button) не знает об атрибуте colorPrimary, поэтому он игнорируется.
Представление получает свои атрибуты из файла макета или атрибута стиля. Если стиль представления включает атрибут темы, он будет проигнорирован.
Как же тогда изменить атрибуты темы только для одного представления? Здесь на помощь приходит наложение тем.
Наложение тем
Наложение тем — это техника, используемая при переопределении атрибутов темы для любого представления или группы представлений. Наложение тем очень полезно, когда вы обновляете тему определенной части вашего приложения.
При применении наложения темы нужно выполнить два шага:
Создайте стиль, состоящий из атрибутов темы, которые необходимо изменить.
Примените этот стиль к файлу макета с помощью android:theme или программно с помощью ContextThemeWrapper .
Давайте продолжим вышеупомянутый сценарий, в котором мы изменяем цвет фона кнопки с помощью атрибута темы colorPrimary . Сначала нам нужно создать стиль для наложения темы, в котором мы зададим colorPrimary .
Наложение темы для кнопки:
У наложения темы нет родительского элемента.
Кроме того, лучше начинать именовать стиль с ThemeOverlay , поскольку так его будет легче отличить от других стилей. Эта техника именования используется также в Material Components и AppCompat.
Давайте применим это наложение к кнопке в файле макета.
Применение наложения темы с помощью атрибута android:theme :
Имейте в виду, что если наложение темы применяется к группе представлений, оно также будет применяться ко всем ее потомкам. Другими словами, тема каждого потомка группы представлений накладывается, когда наложение темы применяется к группе представлений.
Применение наложения темы к группе представлений:
Мы также можем осуществить наложение темы программно, обернув контекст представления с помощью ContextThemeWrapper .
Использование ContextThemeWrapper для наложения темы:
ContextThemeWrapper создает новый контекст (оборачивая заданный) своей собственной темой.
TextAppearance
TextAppearance — это класс, который содержит данные только для стилизации атрибутов TextView , связанных с текстом (например, textColor , textSize , но не связанных с видом, таких как maxLines или drawableTop и т.д.).
TextAppearance устанавливается атрибутом android:textAppearance на TextView . Атрибут android:textAppearance работает так же, как и атрибут style . Основное различие заключается в порядке приоритета между ними. style имеет приоритет над android:textAppearance , что означает, что style всегда будет превалировать над общими атрибутами.
Вы можете спросить, зачем он нам нужен, ведь мы можем задать все в style ? Ответ заключается в том, что мы получаем возможность устанавливать только атрибуты, связанные с текстом, и это делает его многократно используемым для всех TextViews , оставляя атрибут style свободным.
Например, давайте создадим внешний вид текста для заголовка.
Использование стиля TextAppearance.StylesNThemes.Header в качестве оформления внешнего вида текста:
Как видите, атрибут style для TextView является свободным и может использоваться для настройки других атрибутов представления. Вы также можете установить android:textAppearance , создав стиль.
Давайте создадим стиль однострочного заголовка.
Однострочный стиль заголовка:
Теперь вы можете установить этот стиль с помощью атрибута style и повторно использовать его для любого текста.
Применение однострочного стиля заголовка к текстовому представлению:
Если вы хотите более глубоко погрузиться в изучение темы внешнего вида текста и приоритета стилей, я настоятельно рекомендую вам прочитать эту статью.
Заключение
Атрибуты являются ключевым понятием в стилизации и темизации. Используйте атрибуты представления для их стиля и атрибуты темы для приложения, Активности или иерархии представлений. Если вы хотите изменить стиль для всех инстансов данного типа представления во всем приложении, вам подойдут стили по умолчанию. Наложения тем используются для переопределения атрибутов темы, и вы можете использовать их даже для представлений в заданной иерархии. Внешний вид текста может помочь вам сформировать текстовые атрибуты TextViews с помощью android: textAppearance , оставляя атрибут style свободным.
Android-разработчиков с опытом от 3 лет и всех желающих приглашаем на онлайн-интенсив «Полный coverage. Покрываем Android-приложение юнит/интеграционными/UI тестами».
На интенсиве мы:
— Научимся покрывать android приложение юнит/интеграционными/UI тестами.
— Рассмотрим различные кейсы: покрытие тестами suspend функций, RX цепочек.
— Изучим популярные инструменты для написания тестов.
— Обсудим best practices по покрытию тестами.
Источник