Кроме применение отдельных стилей к отдельным элементам, мы можем задавать стили для всего приложения или activity в виде тем. Тема предтавляет коллекцию атрибутов, которые применяются в целом ко всему приложению, классу activity или иерархии виджетов.
Мы можем сами создать тему. Однако Android уже предоставляет несколько предустановленных тем для стилизации приложения,
например, Theme.AppCompat.Light.DarkActionBar и ряд других.
По умолчанию приложение уже применяет темы. Так, откроем файл AndroidManifest.xml. В нем мы можем увидеть следующее определение элемента application, представляющего приложение:
<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/Theme.ViewApp">
Задание темы происходит с помощью атрибута android:theme. В данном случае используется ресурс, который называется в моем случае
Theme.ViewApp. По умолчанию файлы тем определены в папке res/values.
В частности, здесь можно найти условный каталог themes, в котором по умолчанию есть два элемента: themes.xml:
Один файл представляет светлую тему, а другой - темную. Например, откроем файл themes.xml со светлой темой:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.ViewApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
Здесь мы можем увидеть, что тема определяется как и стиль с помощью элемента style.. Атрибут parent указывает на родительскую тему, от которой текущая тема берет все стилевые характеристики. То есть тема "Theme.ViewApp" использует другую тему - "Theme.MaterialComponents.DayNight.DarkActionBar". И кроме того, определяет ряд своих собственных стилей.
Также можно заметить, что здесь определяются не только характеристики для атрибутов, но и семантические имена, например, colorPrimary, которому сопоставлен ресурс "@color/purple_500".
При необходимости мы можем изменить эти характеристики или дополнить тему новыми стилевыми характеристиками. Например, изменим цвет свойства colorPrimary, которое применяется в том числе
в качестве фонового цвета заголовка и кнопки:
<item name="colorPrimary">#1565C0</item>
И соответственно изменится цвет по умолчанию для фона заголовка и кнопки:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Android"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Вместо использования встроенных тем мы можем создать свою. Для этого добавим в папку res/values новый файл mythemes.xml и определим в нем следующее содержимое:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyTheme" parent="Theme.AppCompat.Light">
<item name="android:textColor">#FF018786</item>
<item name="android:textSize">28sp</item>
</style>
</resources>
Итак, мы создали стиль "MyTheme", который унаследован от стиля Theme.AppCompat.Light. В этом стиле мы переопределили
два свойства: высоту шрифта (textSize) - 28sp, а также цвет текста (textColor) - #FF018786.
Теперь определим этот стиль в качестве темы приложения в файле AndroidManifest.xml:
<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/MyTheme"><!-- применение темы -->
Пусть у нас будет следующая разметка в activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Android Lollipop"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/textView2"
/>
<TextView
android:id="@+id/textView2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Android Marshmallow"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toTopOf="@+id/textView3"
app:layout_constraintTop_toBottomOf="@+id/textView1"
/>
<TextView
android:id="@+id/textView3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Android Nougat"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
Как видно, для элементов TextView не устанавливается атрибут textSize и textColor, однако поскольку они определены в теме,
которая применяется глобально к нашему приложению, то элементы TextView будут подхватывать эти стилевые характеристики:
Выше темы применялись глобально ко всему приложению. Но также можно применить их к отдельному классу Activity. Для этого надо подкоррективать файл манифеста AndroidManifest. Например:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.viewapp"
android:versionCode="1"
android:versionName="1.0">
<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/Theme.ViewApp">
<activity android:name=".MainActivity" android:theme="@style/MyTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Атрибут android:theme элемента <activity> указывает на применяемую к MainActivity тему. То есть глобально к приложению применяется
тема "Theme.ViewApp", а к MainActivity - "MyTheme".
Также можно применить тему к иерархии виджетов, установив атрибут android:theme у элемента, к которому (включая его вложенные элементы) мы хотим применить тему. Например, примение темы к ConstraintLayout и ее элементам:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:theme="@style/MyTheme">
<TextView
android:id="@+id/textView1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Android Lollipop"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>