Темы и стили в Android без магии. И как их готовить с SwitchCompat
В предыдущей статье мы рассмотрели, как использовать темы и стили на уровне кода на примере кастомной view. В этой статье давайте разберем несколько способов стилизации стандартного ui элемента, а в частности SwitchCompat.
Введение
Не всегда оформление по умолчанию стандартного UI элемента устраивает дизайнера. Давайте разберем, как поменять внешний вид элемента на примере SwitchCompat.
Для решения задачи нам нужно:
- Создать свой стиль для SwitchCompat.
- Каким-то образом задать этот стиль SwitchCompat.
Назначить стиль SwitchCompat можно несколькими способами, например:
- Указывать для каждой view в верстке экранов через атрибут style.
- Создать тему с переопределенным атрибутом switchStyle и назначить эту тему в манифесте для всего приложения или конкретной активити. Это изменит внешний вид view для всего приложения/активити.
- Тему также можно установить программно, в коде активити. При необходимости ее можно менять «на лету».
Новый стиль для SwitchCompat
В ресурсах создадим новый стиль MySwitchStyle, наследуем оформление от Widget.AppCompat.CompoundButton.Switch, задав parent. Можно и не наследовать, но тогда придется указать все значения, даже которые мы не планируем менять.
<style name="MySwitchStyle" parent = "Widget.AppCompat.CompoundButton.Switch"> </style>
Чтобы что-то изменить, надо переопределить требуемые атрибуты. Атрибуты можно посмотреть в документации.
В документации видим несколько атрибутов. Они указаны в виде, как если бы мы обращались к ним в коде (например, вот так R.styleable.SwitchCompat_android_thumb). Я расшифрую только часть из них, чтобы не было сомнений. Назначение остальных несложно понять из документации.
- android:thumb — ресурс для подвижной части SwitchCompat,
- track — ресурс для неподвижной части SwitchCompat,
- thumbTint — позволяет окрашивать подвижную часть в нужные цвета в зависимости от состояния SwitchCompat,
- trackTint — позволяет окрашивать неподвижную часть в нужные цвета в зависимости от состояния SwitchCompat.
В качестве примера изменим цвет thumb (кружочка) — пусть во включенном состоянии он будет оранжевым, в выключенном — зеленым. Некрасиво, но наглядно.
Нам понадобится селектор в папке color наших ресурсов. Файл selector_switch_thumb.xml:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true" android:color="@android:color/holo_orange_dark"/> <item android:color="@android:color/holo_green_light"/> </selector>
Теперь зададим атрибут thumbTint в нашем стиле.
<style name="MySwitchStyle" parent="Widget.AppCompat.CompoundButton.Switch"> <item name="thumbTint">@color/selector_switch_thumb</item> </style>
Теперь все SwitchCompat, получившие каким-то образом стиль MySwitchStyle, будут выглядеть по-новому.
Стиль в верстке
Самый тривиальный и негибкий способ.
- Стиль применяется при inflate ресурса layout.
- Повлиять программно мы никак не можем.
- Указывать каждый раз в верстке неудобно. И можем забыть.
<androidx.appcompat.widget.SwitchCompat android:text="Themed switch" style="@style/MySwitchStyle" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
Стиль в теме. Тема назначается через Manifest
Создаем тему AppTheme и задаем значение атрибуту switchStyle. Значением является наш стиль MySwitchStyle.
<resources> <style name="CustomTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <!-- Задаем значение атрибуту switchStyle --> <item name="switchStyle">@style/MySwitchStyle</item> </style> </resources>
Тема может быть указана в манифесте для всего приложения
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/CustomTheme"> <!-- Тема для всего приложения --> </application>
Или для конкретной активити
<activity android:name=".MainActivity" android:theme="@style/CustomTheme"> <!-- Тема для активити --> </activity>
Теперь все SwitchCompat будут иметь новый внешний вид. Без изменения в верстке.
- Плюсы — Можем менять внешний вид для всего приложения сразу.
- Минусы — налету менять не получится.
Стиль в теме. Тема назначается программно
Для того чтобы установить тему для активити программно, нужно вызвать метод активити setTheme(themeResId).
Давайте менять тему активити в зависимости от состояния Switch.
private const val KEY_CUSTOM_THEME_CHECKED = "KEY_CUSTOM_THEME_CHECKED" class MainActivity : AppCompatActivity() { private val preference by lazy { PreferenceManager.getDefaultSharedPreferences(this) } override fun onCreate(savedInstanceState: Bundle?) { val isCustomThemeChecked = preference.getBoolean(KEY_CUSTOM_THEME_CHECKED, true) if (isCustomThemeChecked) { setTheme(R.style.CustomTheme) } else { setTheme(R.style.StandardTheme) } super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) customThemeCheckbox.isChecked = isCustomThemeChecked customThemeCheckbox.setOnCheckedChangeListener { _, isChecked -> preference.edit() .putBoolean(KEY_CUSTOM_THEME_CHECKED, isChecked) .apply() recreate() } } }
1. Устанавливаем тему программно, вызвав setTheme. Метод надо вызывать до super.onCreate(savedInstanceState). В onCreate у нас происходит инициализация фрагментов (когда они есть).
- Задаем начальное состояние Switch в зависимости от темы.
- Устанавливаем листенер, который при изменении Switch меняет тему в настройках и перезапускает активити через метод активити recreate().
Результат:
Остальной код
<resources> <style name="CustomTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="switchStyle">@style/MySwitchStyle</item> </style> <style name="StandardTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="MySwitchStyle" parent="Widget.AppCompat.CompoundButton.Switch"> <item name="thumbTint">@color/selector_switch_thumb</item> </style> </resources>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical"> <CheckBox android:text="CustomTheme" android:layout_width="match_parent" android:layout_height="wrap_content" android:saveEnabled="false" android:id="@+id/customThemeCheckbox"/> <androidx.appcompat.widget.SwitchCompat android:text="Themed switch" android:layout_marginTop="56dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/themedSwitch"/> </LinearLayout>
Другие View
Чтобы переопределить стиль для SwitсhView для всего приложения, мы переопределили значение атрибута switchStyle. Можно догадаться, что такие атрибуты есть и для других View.
Например:
- editTextStyle
- checkboxStyle
- radioButtonStyle
Как их искать? Я просто смотрю исходники через Android Studio.
Заходим в тему, зажимаем ctrl, кликаем на родителе нашей темы. Смотрим, как описывают тему ребята из Google. Смотрим, какой атрибут определяется и от какого стиля можно отнаследоваться. Пользуемся.
Кусок из темы Base.V7.Theme.AppCompat.Light.
<item name="editTextStyle">@style/Widget.AppCompat.EditText</item> <item name="checkboxStyle">@style/Widget.AppCompat.CompoundButton.CheckBox</item> <item name="radioButtonStyle"> @style/Widget.AppCompat.CompoundButton.RadioButton</item> <item name="buttonStyle">@style/Widget.AppCompat.Button</item>
Ресурсы
developer.android.com/guide/topics/ui/look-and-feel/themes
developer.android.com/reference/android/support/v7/widget/SwitchCompat.html#xml-attributes
P.S.
Статья не претендует на полный справочник. Код умышленно сокращен. Я ставил задачу дать общее понимание — как это работает и зачем это нужно. Дальше все легко ищется в документации и в стандартных ресурсах.
Источник: Темы и стили в Android без магии. И как их готовить с SwitchCompat