Przejdź do treści
School IT / Przestrzeń do nauki

school-it.pl // android + kotlin // rozdział 5 // lekcja 18

Selektory stanów i style

Przycisk z kształtem z lekcji 17 wygląda tak samo, gdy go naciskasz, i tak samo, gdy jest wyłączony — użytkownik nie widzi reakcji. Selektor dobiera wygląd do stanu kontrolki: inny przy naciśnięciu, inny po wyłączeniu, inny po zaznaczeniu. Styl zbiera powtarzające się atrybuty w jednym miejscu, więc dwanaście jednakowych przycisków nie wymaga dwunastu kopii tych samych linii. Oba połączysz, budując klawiaturę PIN.

Kotlin XML selector state_pressed state_enabled state_selected style themes.xml 2 × 45 min
CEL LEKCJI

Czego się dziś nauczysz

  • Zbudujesz selektor tła z osobnym kształtem dla stanu naciśnięcia i wyłączenia.
  • Zbudujesz selektor koloru tekstu w folderze res/color.
  • Sterujesz wyglądem z kodu przez stan isSelected.
  • Zapiszesz wspólne atrybuty w stylu i użyjesz go w wielu kontrolkach.
  • Zmienisz kolor główny całej aplikacji w motywie.
TEORIA

Selektor tła

Selektor to plik w res/drawable z elementem <selector>. Zawiera listę <item> — każdy opisuje wygląd w innym stanie. Android sprawdza je od góry i bierze pierwszy pasujący:

res/drawable/tlo_przycisk.xml — trzy stany
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 1. wyłączony -->
    <item android:state_enabled="false">
        <shape android:shape="rectangle">
            <solid android:color="#E0E0E0" />
            <corners android:radius="12dp" />
        </shape>
    </item>

    <!-- 2. naciśnięty -->
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#4F378B" />
            <corners android:radius="12dp" />
        </shape>
    </item>

    <!-- 3. każdy inny stan — ZAWSZE na końcu, bez warunku -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#6750A4" />
            <corners android:radius="12dp" />
        </shape>
    </item>
</selector>

Kształt można wpisać bezpośrednio w <item> (jak wyżej) albo wskazać osobny plik: <item android:state_pressed="true" android:drawable="@drawable/ksztalt_nacisniety" />. Selektor podpinasz jak zwykły kształt: android:background="@drawable/tlo_przycisk" — na AppCompatButton (lekcja 17).

Kolejność ma znaczenie

Element bez warunku pasuje do każdego stanu. Gdy stoi na początku, Android zawsze wybierze jego i nigdy nie dojdzie do stanów niżej. Element domyślny zawsze dawaj na koniec.

TEORIA

Stany kontrolki

StanKiedy jest prawdziwyKto go ustawia
state_pressedPalec dotyka kontrolki.Android, sam.
state_enabledKontrolka jest włączona.Ty: isEnabled.
state_checkedPole wyboru / przełącznik zaznaczony.Użytkownik lub isChecked.
state_selectedKontrolka oznaczona jako wybrana.Tylko ty: isSelected = true.
state_focusedKontrolka ma fokus (np. pole tekstowe z kursorem).Android.

Stan state_selected jest szczególnie wygodny: każda kontrolka, nawet zwykły View, ma właściwość isSelected, a selektor sam zmieni jej wygląd. Nie trzeba w kodzie podmieniać tła ani kolorów — wystarczy przestawić true / false.

12:30
OK
OK
OK
domyślnypressedenabled=false
cztery View z selektorem; dwa mają isSelected = true
ten sam selektor w różnych stanach
TEORIA

Selektor koloru tekstu

Gdy tło naciśniętego przycisku robi się ciemne, tekst też powinien zmienić kolor. Selektor koloru umieszcza się w osobnym folderze res/color (prawy przycisk na res → New → Android Resource Directory → typ color), a jego elementy mają atrybut android:color:

res/color/tekst_przycisk.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#9E9E9E" android:state_enabled="false" />
    <item android:color="#FFFFFF" android:state_pressed="true" />
    <item android:color="#1D1B20" />
</selector>

Używasz go jak zwykłego koloru: android:textColor="@color/tekst_przycisk".

TEORIA

Styl — wspólne atrybuty

Dwanaście przycisków klawiatury ma ten sam rozmiar, tło, kolor i wielkość tekstu. Zamiast powtarzać te atrybuty dwanaście razy, zapisujesz je raz jako styl w res/values/themes.xml (albo w osobnym pliku styles.xml w tym samym folderze):

res/values/themes.xml — styl dopisany wewnątrz <resources>
<style name="Klawisz">
    <item name="android:layout_width">72dp</item>
    <item name="android:layout_height">72dp</item>
    <item name="android:textSize">26sp</item>
    <item name="android:background">@drawable/tlo_klawisz</item>
</style>

<!-- styl potomny: wszystko z Klawisz + czerwony tekst -->
<style name="Klawisz.Usun">
    <item name="android:textColor">#C62828</item>
</style>
w układzie — atrybut style bez przedrostka android:
<androidx.appcompat.widget.AppCompatButton
    android:id="@+id/btn7"
    style="@style/Klawisz"
    android:text="7" />
ZasadaZnaczenie
atrybut w kontrolce wygrywa ze stylemStyl ustala wartości domyślne; kontrolka może nadpisać dowolną z nich.
Klawisz.UsunNazwa z kropką tworzy styl potomny — dziedziczy wszystko po Klawisz.
parent="…"Inny zapis dziedziczenia, np. po stylu biblioteki Material: parent="Widget.Material3.Button".
jeden styl na kontrolkęAtrybut style przyjmuje tylko jeden styl.
TEORIA

Motyw aplikacji

W tym samym pliku themes.xml jest już styl o nazwie Theme.NazwaProjektu. To motyw — styl dla całej aplikacji, podpięty w manifeście. Zmienia wygląd wszystkich ekranów naraz. Najważniejszy jest kolor główny:

res/values/themes.xml — motyw z szablonu z dopisanymi kolorami
<style name="Base.Theme.Pin" parent="Theme.Material3.DayNight.NoActionBar">
    <item name="colorPrimary">#00696D</item>     <!-- przyciski, przełączniki, suwaki -->
    <item name="colorOnPrimary">#FFFFFF</item>   <!-- tekst na kolorze głównym -->
</style>

Po tej zmianie wszystkie zwykłe przyciski, przełączniki, pola wyboru i suwaki w aplikacji staną się morskie — bez dotykania układów. Kontrolki z własnym tłem (selektorem) zachowają swój wygląd. Uwaga: plik themes.xml jest też w folderze values-night — dla trybu ciemnego. Zmieniaj kolory w obu.

PRZYKŁAD

Klawiatura PIN

Ekran blokady z okrągłymi klawiszami. Wszystkie klawisze korzystają z jednego stylu, a selektor pokazuje naciśnięcie i blokadę. Cztery kropki nad klawiaturą wypełniają się w miarę wpisywania — selektorem sterowanym przez isSelected. Poprawny PIN (2580) odblokowuje ekran. Po trzech błędnych próbach klawiatura blokuje się na 10 sekund — klawisze szarzeją same dzięki stanowi state_enabled.

7:05
Wpisz PIN
 
123 456 789 ⌫0OK
2 cyfry wpisane, „5” w chwili naciśnięcia, OK wyłączone
7:06
Wpisz PIN
Zablokowano. Spróbuj za 7 s
123 456 789 ⌫0OK
po 3 błędach — wszystkie klawisze wyłączone

wygląd wyłączonych klawiszy zmienia selektor — kod ustawia tylko isEnabled = false

Przygotowanie projektu

  1. Nowy projekt Empty Views Activity, nazwa Pin, Kotlin, API 24.
  2. Utwórz folder res/color i w nim plik tekst_klawisz.xml. W res/drawable utwórz tlo_klawisz.xml i kropka.xml (Root element: selector).
  3. Dopisz dwa style do res/values/themes.xml — pod istniejącymi stylami motywu, wewnątrz <resources>.
  4. Podmień activity_main.xml i MainActivity.kt.
res/
├── color/
│   └── tekst_klawisz.xmlnowy folder i plik
├── drawable/
│   ├── tlo_klawisz.xmlselektor tła klawisza
│   └── kropka.xmlselektor kropki
├── layout/
│   └── activity_main.xml
└── values/
    └── themes.xmldopisane style Klawisz i Klawisz.Usun
res/drawable/tlo_klawisz.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="false">
        <shape android:shape="oval">
            <solid android:color="#E0E0E0" />
        </shape>
    </item>
    <item android:state_pressed="true">
        <shape android:shape="oval">
            <solid android:color="#6750A4" />
        </shape>
    </item>
    <item>
        <shape android:shape="oval">
            <solid android:color="#E8DEF8" />
        </shape>
    </item>
</selector>
res/color/tekst_klawisz.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#9E9E9E" android:state_enabled="false" />
    <item android:color="#FFFFFF" android:state_pressed="true" />
    <item android:color="#1D1B20" />
</selector>
res/drawable/kropka.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- wybrana: pełne koło -->
    <item android:state_selected="true">
        <shape android:shape="oval">
            <solid android:color="#6750A4" />
        </shape>
    </item>
    <!-- pozostałe: sam obrys -->
    <item>
        <shape android:shape="oval">
            <stroke android:width="2dp" android:color="#79747E" />
        </shape>
    </item>
</selector>
res/values/themes.xml — dopisz wewnątrz <resources>
<!-- wspólny wygląd dwunastu klawiszy -->
<style name="Klawisz">
    <item name="android:layout_width">72dp</item>
    <item name="android:layout_height">72dp</item>
    <item name="android:layout_margin">8dp</item>
    <item name="android:background">@drawable/tlo_klawisz</item>
    <item name="android:textColor">@color/tekst_klawisz</item>
    <item name="android:textSize">26sp</item>
</style>

<!-- klawisz kasowania: wszystko jak Klawisz, ale czerwony znak -->
<style name="Klawisz.Usun">
    <item name="android:textColor">#C62828</item>
</style>
res/layout/activity_main.xml — pełny plik
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Wpisz PIN"
        android:textSize="24sp" />

    <!-- cztery kropki -->
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:orientation="horizontal">
        <View android:id="@+id/kropka1" android:layout_width="16dp" android:layout_height="16dp"
            android:layout_margin="8dp" android:background="@drawable/kropka" />
        <View android:id="@+id/kropka2" android:layout_width="16dp" android:layout_height="16dp"
            android:layout_margin="8dp" android:background="@drawable/kropka" />
        <View android:id="@+id/kropka3" android:layout_width="16dp" android:layout_height="16dp"
            android:layout_margin="8dp" android:background="@drawable/kropka" />
        <View android:id="@+id/kropka4" android:layout_width="16dp" android:layout_height="16dp"
            android:layout_margin="8dp" android:background="@drawable/kropka" />
    </LinearLayout>

    <TextView
        android:id="@+id/tvKomunikat"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:minHeight="24dp"
        android:textSize="16sp" />

    <!-- cztery rzędy po trzy klawisze; rozmiar, tło i kolor z jednego stylu -->
    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn1" style="@style/Klawisz" android:text="1" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn2" style="@style/Klawisz" android:text="2" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn3" style="@style/Klawisz" android:text="3" />
    </LinearLayout>
    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn4" style="@style/Klawisz" android:text="4" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn5" style="@style/Klawisz" android:text="5" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn6" style="@style/Klawisz" android:text="6" />
    </LinearLayout>
    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn7" style="@style/Klawisz" android:text="7" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn8" style="@style/Klawisz" android:text="8" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn9" style="@style/Klawisz" android:text="9" />
    </LinearLayout>
    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content">
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btnUsun" style="@style/Klawisz.Usun"
            android:contentDescription="Usuń ostatnią cyfrę" android:text="⌫" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btn0" style="@style/Klawisz" android:text="0" />
        <androidx.appcompat.widget.AppCompatButton android:id="@+id/btnOk" style="@style/Klawisz"
            android:text="OK" android:textSize="18sp" />
    </LinearLayout>

</LinearLayout>
MainActivity.kt — pełny plik
package pl.schoolit.pin

import android.graphics.Color
import android.os.Bundle
import android.os.CountDownTimer
import android.view.View
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val tvKomunikat = findViewById<TextView>(R.id.tvKomunikat)
        val btnUsun = findViewById<Button>(R.id.btnUsun)
        val btnOk = findViewById<Button>(R.id.btnOk)

        // dziesięć klawiszy cyfr i cztery kropki w tablicach — obsłużymy je pętlą
        val cyfry = arrayOf(
            findViewById<Button>(R.id.btn0), findViewById<Button>(R.id.btn1),
            findViewById<Button>(R.id.btn2), findViewById<Button>(R.id.btn3),
            findViewById<Button>(R.id.btn4), findViewById<Button>(R.id.btn5),
            findViewById<Button>(R.id.btn6), findViewById<Button>(R.id.btn7),
            findViewById<Button>(R.id.btn8), findViewById<Button>(R.id.btn9)
        )
        val kropki = arrayOf(
            findViewById<View>(R.id.kropka1), findViewById<View>(R.id.kropka2),
            findViewById<View>(R.id.kropka3), findViewById<View>(R.id.kropka4)
        )

        val poprawnyPin = "2580"
        var pin = ""
        var bledy = 0

        fun pokazStan() {
            // kropka nr i jest „wybrana”, gdy wpisano więcej niż i cyfr — selektor zrobi resztę
            for (i in kropki.indices) {
                kropki[i].isSelected = i < pin.length
            }
            btnUsun.isEnabled = pin.isNotEmpty()
            btnOk.isEnabled = pin.length == 4
        }

        fun ustawKlawiature(wlaczona: Boolean) {
            for (k in cyfry) {
                k.isEnabled = wlaczona
            }
            if (wlaczona) {
                pokazStan()                  // Usuń i OK zależą od długości PIN-u
            } else {
                btnUsun.isEnabled = false
                btnOk.isEnabled = false
            }
        }

        pokazStan()

        // jeden kod dla wszystkich cyfr: cyfrę bierzemy z napisu klawisza
        for (k in cyfry) {
            k.setOnClickListener {
                if (pin.length < 4) {
                    pin += k.text
                    tvKomunikat.text = ""
                    pokazStan()
                }
            }
        }

        btnUsun.setOnClickListener {
            pin = pin.dropLast(1)            // napis bez ostatniego znaku
            pokazStan()
        }

        btnOk.setOnClickListener {
            if (pin == poprawnyPin) {
                tvKomunikat.text = "Odblokowano!"
                tvKomunikat.setTextColor(Color.parseColor("#2E7D32"))
                ustawKlawiature(false)
                return@setOnClickListener
            }

            bledy++
            pin = ""
            pokazStan()
            tvKomunikat.setTextColor(Color.parseColor("#C62828"))

            if (bledy < 3) {
                tvKomunikat.text = "Błędny PIN. Pozostało prób: ${3 - bledy}"
                return@setOnClickListener
            }

            // trzeci błąd: blokada na 10 sekund
            ustawKlawiature(false)
            object : CountDownTimer(10_000, 1000) {
                override fun onTick(pozostalo: Long) {
                    tvKomunikat.text = "Zablokowano. Spróbuj za ${pozostalo / 1000 + 1} s"
                }

                override fun onFinish() {
                    bledy = 0
                    tvKomunikat.text = ""
                    ustawKlawiature(true)
                }
            }.start()
        }
    }
}

Co dzieje się po kolei

  • Każdy klawisz w XML ma tylko id, style i tekst. Rozmiar, margines, tło i kolor przychodzą ze stylu Klawisz. Klawisz kasowania używa Klawisz.Usun — tego samego wyglądu z czerwonym znakiem.
  • Tło klawisza to selektor: fioletowe koło przy naciśnięciu, szare przy wyłączeniu, jasne w pozostałych przypadkach. Kolor tekstu zmienia drugi selektor — z folderu res/color.
  • Klawisze cyfr są w tablicy, a setOnClickListener ustawiamy w pętli. Cyfrę bierzemy z napisu klikniętego klawisza — k.text.
  • Kropki to zwykłe View z selektorem. Kod przestawia tylko isSelected, a selektor podmienia obrys na pełne koło.
  • Po trzecim błędzie ustawKlawiature(false) wyłącza wszystko. Szary wygląd to zasługa selektora (state_enabled="false"), nie kodu.
  • pin.dropLast(1) zwraca napis bez ostatniego znaku — tak działa kasowanie.

Sprawdź trzy rzeczy

  1. Przytrzymaj palec na klawiszu — tło jest fioletowe, a cyfra biała, dopóki go nie puścisz.
  2. Przenieś w tlo_klawisz.xml ostatni <item> (bez warunku) na samą górę. Klawisze przestaną reagować wyglądem na dotyk i blokadę.
  3. Zmień w stylu Klawisz rozmiar na 64dp. Zmienią się wszystkie klawisze naraz.
ELEMENTY WBUDOWANE

Zestawienie elementów

ElementTypCo robi
<selector> + <item android:state_…>drawable / colorWygląd zależny od stanu; pierwszy pasujący wygrywa.
state_pressed, state_enabled, state_checked, state_selectedstanyNaciśnięty, włączony, zaznaczony, wybrany.
res/color/…xmlzasóbSelektor koloru (android:color).
view.isSelectedBooleanStan „wybrany” ustawiany z kodu.
<style name="…"><item name="…">zasóbZestaw atrybutów pod jedną nazwą.
style="@style/…"atrybutUżycie stylu w kontrolce.
Nazwa.Potomny, parent="…"dziedziczenieStyl przejmujący atrybuty innego.
colorPrimary, colorOnPrimarymotywKolor główny aplikacji i tekstu na nim.
napis.dropLast(n)StringNapis bez n ostatnich znaków.
for (k in tablica) k.setOnClickListener { }pętlaTen sam listener dla wielu kontrolek.
CZĘSTE BŁĘDY

Zanim utkniesz

Zapis / objawProblem
selektor zawsze pokazuje stan domyślnyElement bez warunku stoi przed innymi. Przenieś go na koniec.
selektor koloru w res/drawableBłąd przy textColor: …is not a color. Selektory kolorów idą do res/color.
android:style="@style/Klawisz"Styl jest ignorowany. Atrybut style pisze się bez przedrostka android:.
styl na <Button> — tło się nie zmieniaPrzycisk Material przemalowuje tło. Używaj AppCompatButton (lekcja 17).
kolor motywu zmienia się tylko w trybie jasnymTryb ciemny ma osobny values-night/themes.xml.
isSelected = true nic nie zmieniaTło kontrolki nie jest selektorem ze stanem state_selected.
klawisze nie mieszczą się na małym ekranieStały rozmiar 72dp w stylu. Zmniejsz go w jednym miejscu — w stylu.
ZADANIA

Zadania

Każde zadanie wykonaj w nowym projekcie Empty Views Activity. Cały kod pisz w onCreate. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.

ZAD 1Przycisk z reakcją★☆☆

Przycisk w kształcie pigułki z ramką: w spoczynku biały z fioletową ramką i fioletowym tekstem, po naciśnięciu fioletowy z białym tekstem, wyłączony — szary. Drugi przycisk włącza i wyłącza pierwszy.

pokaż wskazówkę
  • Dwa selektory: tła w drawable i tekstu w color. Przycisk: AppCompatButton.
ZAD 2Własny CheckBox★☆☆

Trzy pola wyboru z własnym wyglądem: zamiast kwadracika — pigułka na całą szerokość, szara gdy niezaznaczona, zielona z białym tekstem gdy zaznaczona.

pokaż wskazówkę
  • Selektor ze stanem state_checked jako android:background, a domyślny kwadracik ukryj atrybutem android:button="@null".
ZAD 3Zakładki dni tygodnia★★☆

Siedem małych kafelków z literami P W Ś C P S N w jednym rzędzie. Dotknięcie kafelka czyni go wybranym (pełny kolor), a poprzednio wybrany wraca do zwykłego wyglądu. Pod spodem napis z pełną nazwą dnia. Wszystkie kafelki korzystają z jednego stylu.

pokaż wskazówkę
  • Selektor z state_selected. W listenerze pętlą ustaw isSelected = false wszystkim, a potem true klikniętemu.
ZAD 4Style hierarchiczne★★☆

Ekran z nagłówkiem, trzema akapitami tekstu i dwoma przypisami. Zdefiniuj styl Tekst (rozmiar, kolor, odstęp linii) i trzy potomne: Tekst.Naglowek (większy, pogrubiony), Tekst.Akapit (wcięcie pierwszej linii — margines), Tekst.Przypis (mniejszy, kursywa, szary). Zmiana koloru w stylu Tekst ma zmienić wszystkie napisy.

pokaż wskazówkę
  • Styl potomny przez kropkę w nazwie dziedziczy wszystkie atrybuty — dopisuj w nim tylko to, co inne.
ZAD 5Motyw szkolny★★☆

Weź dowolny projekt z rozdziałów 2–4 (np. kasę kina z lekcji 10) i zmień jego motyw na kolory szkoły: colorPrimary, colorOnPrimary, colorSecondary. Zmiany mają objąć tryb jasny i ciemny. Nie zmieniaj żadnego pliku układu.

pokaż wskazówkę
  • Dwa pliki: values/themes.xml i values-night/themes.xml. Tryb ciemny na emulatorze: Ustawienia → Wyświetlacz → Ciemny motyw.
ZAD 6Kalkulator z klawiaturą★★★

Kalkulator czterech działań na liczbach całkowitych. Trzy style klawiszy: Klawisz.Cyfra, Klawisz.Dzialanie (inny kolor tła — osobny selektor), Klawisz.Rownasie (szerszy). Klawisze działań są wyłączone, dopóki nie wpisano pierwszej liczby; po wybraniu działania jego klawisz pozostaje „wybrany” (state_selected) aż do wpisania drugiej liczby.

pokaż wskazówkę
  • Stan kalkulatora: var liczba1, var dzialanie: String?, var biezaca = "". Cyfry i działania obsłuż pętlami po tablicach — jak w przykładzie.
PODSUMOWANIE

Co trzeba zapamiętać

  • Selektor wybiera wygląd według stanu; element bez warunku zawsze na końcu.
  • Selektory tła — w res/drawable, selektory kolorów — w res/color.
  • isSelected i isEnabled z kodu + selektor = zmiana wyglądu bez podmieniania tła.
  • Styl zbiera wspólne atrybuty; style="@style/…" bez android:; dziedziczenie przez kropkę.
  • Motyw w themes.xml zmienia kolory całej aplikacji — pamiętaj o values-night.

Dokumentacja: Selektor (StateListDrawable), Selektor kolorów, Style i motywy.

Postęp zapisuje się w tej przeglądarce.