Темы и стили в 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