Motywy aktywności (theme activity)
Motyw (Theme) w systemie Android są podobnie zorganizowane jak style. Standardowo pliki XML motywów zapisywane są w lokalizacji res/values. Motyw jest zbiorem atrybutów, który jest zastosowany do całej aplikacji, hierarchii widoków. Motyw może nadać styl elementom takim jak pasek stanu, tło okna. Motyw często określa wygląd aplikacji w trybie dzień/ noc. Przypisanie motywu do aplikacji lub pojedynczej aktywności rozbudowanej aplikacji odbywa się w pliku manifestu.
Zastosowanie motywu do całej aplikacji wymaga poniżej konstrukcji w pliku manifestu
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<manifest >
<application android:theme="@style/Theme.GlownyMotyw" >
</application>
</manifest>
Dla konkretnej pojedynczej aktywności w pliku manifestu składnia jest podobna, ale zastosowanie wymaga użycia jej w elemencie potomnym <activity> elementu <application>
Wskazówka:
<manifest ... >
<application ... >
<activity android:theme="@style/Theme.DrugiMotyw" ... >
</activity>
</application>
</manifest>
Zasoby kolorów
W pliku zasobów kolorów (colors.xml) dodamy kilka różnych kolorów przy pomocy, których zdefiniujemy dwa rożne motywy aplikacji
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="czerwony">#F80303</color>
<color name="niebieski1">#00B0FF</color>
<color name="niebieski2">#0356FB</color>
<color name="niebieski3">#02076A</color>
<color name="pomaranczowy">#FF9800</color>
<color name="zielony">#89FF00</color>
<color name="zolty1">#FFEB3B</color>
<color name="zolty2">#FDBE01</color>
<color name="zolty3">#FFEB3B</color>
</resources>
Definicja głównych elementów motywu (theme) aktywności
W naszej aplikacji będziemy motywem zmieniać wybrane atrybuty paska stanu, paska narzędziowego, obszaru okna, paska nawigacyjnego. Zmiany wykonamy poprzez przypisanie kolorów. W tym celu w pliku XML z zapisanym motywem należy odwołać się do poniższych atrybutów colorPrimaryDark, colorPrimary, android:textColorPrimary itp. Patrz poniższa ilustracja
Tworząc nowy motyw (Theme) widoku dobrze jest wskazać dziedziczenie po istniejących motywach zapisanych w bibliotece (Android Support Library). Te dziedziczenie ułatwi podgląd w edytorze tworzenia widoku. Każdy z tak zdefiniowanych motywów pojawi się na liście wyboru podglądu widoku aktywności.
Wybierz filtr motywów
Uwaga. Lista motywów zdefiniowanych w projekcie zależy od ich ilości, pod warunkiem że dziedziczą po dowolnym motywie (theme)
Tworzymy plik XML dla zasobów tworzonych motywów.
W pliku definiujemy nowe dwa motywy. Oba motywy będą dziedziczyć po Theme.AppCompat. Poniżej przykładowa zawartość
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Motyw.Niebieski" parent="Theme.AppCompat">
<item name="colorPrimary">@color/niebieski1</item>
<item name="colorPrimaryDark">@color/pomaranczowy</item>
<item name="android:textColorPrimary">@color/zielony</item>
<item name="android:windowBackground">@color/niebieski3</item>
<item name="android:navigationBarColor">@color/czerwony</item>
</style>
<style name="Motyw.Zolty" parent="Theme.AppCompat">
<item name="colorPrimary">@color/zolty1</item>
<item name="colorPrimaryDark">@color/czerwony</item>
<item name="android:textColorPrimary">@color/niebieski3</item>
<item name="android:windowBackground">@color/zolty3</item>
<item name="android:navigationBarColor">@color/zielony</item>
<item name="android:textColor">@color/czerwony</item>
</style>
</resources>
Przechodzimy do pliku manifestu aplikacji i, jako główny motyw ustawiamy jeden z utworzonych. Patrz linijka kodu android:theme="@style/Motyw.Niebieski"
Zawartość pliku manifestu
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Motyw.Niebieski"
tools:targetApi="31">
<activity
android:name=".OknoGlowne"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
W edytorze podglądu widoku okna aktywność nie zaobserwujesz zmian pasków. Po skompilowaniu aplikacji na wirtualne urządzenie zmiany będą widoczne.
Dynamiczna zmiana motywu aplikacji
Motyw (Theme) aplikacji może również zmienić dynamicznie , czyli w czasie jej działania na przykład po kliknięciu w przycisk. Do widoku aktywności damy dwa komponenty typu Button
Przy zmianie motywu wykorzystamy jedną z metod cyklu życia aplikacji- onReasume(). Metoda ta jest odpowiedzialna z wznowienie aktywności bieżącej aplikacji na przykład po odebraniu połączenia telefonicznego lub innej interakcji z użytkownikiem. W tym przypadki interakcją będzie każdorazowe kliknięcie w przycisk.
W pliku głównej klasy aktywności zdefiniujemy dwie zmienne typu Int do przechowywania stanu wyboru motywu
Wskazówka:
import androidx.appcompat.app.AppCompatActivity
private var idMotyw: Int=0
private var idMotywAktywny:Int=0
class OknoGlowne : AppCompatActivity() {
Dodamy funkcję zmieniającą motyw. Parametrem funkcji będzie identyfikator wybranej opcji
fun UstawMotyw(id:Int){
when(id){
0->setTheme(R.style.Motyw_Niebieski)
else->setTheme(R.style.Motyw_Zolty)
}
}
Obsługę klikania w przyciski wykonamy przez słuchacza kliknięć. Do metody onCreate() wprowadzimy poniższy kod
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
UstawMotyw(idMotywAktywny)
setContentView(R.layout.activity_okno_glowne)
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener{
idMotyw=0//R.style.Motyw_Niebieski
//wywołaj stan wznowienia
recreate()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener{
idMotyw=1//R.style.Motyw_Zolty
//wywołaj stan wznowienia
recreate()
}
}
Zauważ, że po każdorazowym kliknięciu jest wywoływana metoda recreate(). Jest to wbudowana funkcja wywołując odtwarzanie aktywności poprzez cykl życia aplikacji onReasume().
Nadpisujemy metodę onReasume()
Wskazówka:
override fun onResume() {
super.onResume()
if(idMotywAktywny != idMotyw) {
//ustaw id aktywnego motywu
idMotywAktywny= idMotyw
recreate()
}
}
I to tyle w kodowaniu. Pełny kod po zmianach wygląda jak poniżej
Wskazówka:
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
private var idMotyw: Int=0
private var idMotywAktywny:Int=0
class OknoGlowne : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
UstawMotyw(idMotywAktywny)
setContentView(R.layout.activity_okno_glowne)
val bt1=findViewById<Button>(R.id.button1)
bt1.setOnClickListener{
idMotyw=0//R.style.Motyw_Niebieski
//wywołaj stan wznowienia
recreate()
}
val bt2=findViewById<Button>(R.id.button2)
bt2.setOnClickListener{
idMotyw=1//R.style.Motyw_Zolty
//wywołaj stan wznowienia
recreate()
}
}
fun UstawMotyw(id:Int){
when(id){
0->setTheme(R.style.Motyw_Niebieski)
else->setTheme(R.style.Motyw_Zolty)
}
}
//nadpisz stan wznowienia
override fun onResume() {
super.onResume()
if(idMotywAktywny != idMotyw) {
//ustaw id aktywnego motywu
idMotywAktywny= idMotyw
recreate()
}
}
}
Po uruchomieniu aplikacji na wirtualnym emulatorze, dynamiczne zmiany motywu prezentują się jak poniżej
Raczej nie są to motywy zbyt estetyczne, ważne że dynamiczna zmiana motywu działa. Kolorystykę, kształty przycisków itp. można dopracować i otrzymać bardzo estetyczny niepowtarzalny graficzny styl tworzonej aplikacji.