- PVSM.RU - https://www.pvsm.ru -

Темы и стили в Android без магии. И как их готовить с SwitchCompat

Темы и стили в Android без магии. И как их готовить с SwitchCompat - 1
В предыдущей статье [1] мы рассмотрели как использовать темы и стили на уровне кода, на примере кастомной view. В этой статье давайте разберем несколько способов стилизации стандартного ui элемента, а в частности SwitchCompat.

Содержание

Введение [2]
Новый стиль для switchStyle [3]
Стиль в верстке [4]
Стиль в теме. Тема назначается через Manifest. [5]
Стиль в теме. Тема назначается программно. [6]
Другие View [7]

Введение

Не всегда оформление по умолчанию стандартного UI элемента устраивает дизайнера. Давайте разберем, как поменять внешний вид элемента на примере SwitchCompat.

Для решения задачи нам нужно:

  • Создать свой стиль для SwitchCompat.
  • Каким-то образом задать этот стиль SwitchCompat.

Назначить стиль SwitchCompat можно несколькими способами, например:

  • Указывать для каждой view в верстке экранов через атрибут style.
  • Создать тему с переопределенным атрибутом switchStyle и назначить эту тему в манифесте для всего приложения или конкретной активити. Это изменит внешний вид view для всего приложения/активити.
  • Тему также можно установить программно, в коде активити. При необходимости ее можно менять «на лету».

Новый стиль для SwitchCompat

Темы и стили в Android без магии. И как их готовить с SwitchCompat - 2
В ресурсах создадим новый стиль MySwitchStyle, наследуем оформление от Widget.AppCompat.CompoundButton.Switch, задав parent. Можно и не наследовать, но тогда придется указать все значения, даже которые мы не планируем менять.

<style name="MySwitchStyle" parent = "Widget.AppCompat.CompoundButton.Switch">
</style>

Чтобы что-то изменить, надо переопределить требуемые атрибуты. Атрибуты можно посмотреть в документации. [8]
В документации видим несколько атрибутов. Они указаны в виде, как если бы мы обращались к ним в коде (например, вот так R.styleable.SwitchCompat_android_thumb). Я расшифрую только часть из них, чтобы не было сомнений. Назначение остальных несложно понять из документации.

В коде В xml
SwitchCompat_android_thumb android:thumb
SwitchCompat_thumbTint thumbTint
SwitchCompat_track track
SwitchCompat_trackTint trackTint

  • 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, будут выглядеть по-новому.
Темы и стили в Android без магии. И как их готовить с SwitchCompat - 3

Стиль в верстке

Самый тривиальный и негибкий способ.

  • Стиль применяется при 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.

class MainActivity : AppCompatActivity() {

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 у нас происходит инициализация фрагментов (когда они есть).
  2. Задаем начальное состояние Switch в зависимости от темы.
  3. Устанавливаем листенер, который при изменении Switch меняет тему в настройках и перезапускает активити через метод активити recreate().

Результат
Темы и стили в Android без магии. И как их готовить с SwitchCompat - 4

Остальной код

<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 [9]

developer.android.com/reference/android/support/v7/widget/SwitchCompat.html#xml-attributes [8]

P.S.
Статья не претендует на полный справочник. Код умышленно сокращен. Я ставил задачу дать общее понимание — как это работает и зачем это нужно. Дальше все легко ищется в документации и в стандартных ресурсах.

Автор: Дмитрий Берендеев

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/android-development/320945

Ссылки в тексте:

[1] предыдущей статье: https://habr.com/ru/post/453812/

[2] Введение: #introduction

[3] Новый стиль для switchStyle: #new-style

[4] Стиль в верстке: #style-in-layout

[5] Стиль в теме. Тема назначается через Manifest.: #style-in-theme-manifest

[6] Стиль в теме. Тема назначается программно.: #style-in-theme-programmatically

[7] Другие View: #other-view

[8] документации.: https://developer.android.com/reference/android/support/v7/widget/SwitchCompat.html#xml-attributes

[9] developer.android.com/guide/topics/ui/look-and-feel/themes: https://developer.android.com/guide/topics/ui/look-and-feel/themes

[10] Источник: https://habr.com/ru/post/456178/?utm_source=habrahabr&utm_medium=rss&utm_campaign=456178