Error State — to stan pola wprowadzania, który wizualnie sygnalizuje nieprawidłowe dane. W Android Error State jest realizowany przez TextInputLayout.setError(), który podświetla ramkę na czerwono i pokazuje tekst błędu pod polem. Według Material Design Guidelines, 2026, Error State powinien być zauważalny, ale nie agresywny: czerwona ramka, tekst błędu, ikona. Prawidłowe użycie Error State zwiększa konwersję formularzy o 20-30%, ponieważ użytkownik szybko znajduje i naprawia błędy bez utraty kontekstu.
Najważniejsze
Error State — to specjalny tryb wyświetlania pola wprowadzania, który aktywuje się, gdy wprowadzone dane nie przeszły walidacji. Wizualnie Error State obejmuje trzy komponenty: zmianę koloru obramowania lub tła pola (zwykle na czerwony), pojawienie się komunikatu tekstowego pod polem z opisem błędu oraz opcjonalnie — ikonę lub podświetlenie. Celem Error State jest natychmiastowe przyciągnięcie uwagi użytkownika do problematycznego pola i podpowiedzenie, jak naprawić błąd.
W Android Error State jest zaimplementowany na poziomie TextInputLayout z Material Design Components. TextInputLayout otacza EditText i zarządza jego stanami: normal, focused, error, disabled. Metoda setError(String) przełącza pole w stan błędu, zmienia kolor ramki i wyświetla komunikat. Przy zmianie tekstu lub wywołaniu setError(null) pole wraca do normal.
Według Material Design Guidelines, Error State powinien być zauważalny, ale nie dominujący. Czerwony kolor ramki powinien kontrastować z normalnym stanem, ale nie przeciążać interfejsu. Komunikat o błędzie powinien zawierać konkretne informacje o problemie i sposobie jego rozwiązania. Ikona błędu (np. czerwone kółko z wykrzyknikiem) wzmacnia sygnał wizualny.
Metoda setError(CharSequence errorText) przełącza TextInputLayout w stan błędu. Parametr errorText — tekst wyświetlany pod polem. Jeśli przekazać null, błąd jest resetowany. TextInputLayout zarządza animacją: tekst błędu pojawia się z płynnym pojawieniem, ramka zmienia kolor na czerwony. Ikona błędu (domyślnie wykrzyknik w kole) jest wyświetlana na końcu pola.
Ważne szczegóły: setErrorEnabled(true) powinno być wywołane przed setError, aby zarezerwować miejsce pod komunikat o błędzie. W przeciwnym razie przy pojawieniu się błędu układ może „skoczyć”, ponieważ miejsce pod komunikat nie jest zarezerwowane. Zaleca się zawsze włączać obsługę błędu w XML przez app:errorEnabled="true", aby uniknąć przesunięcia układu.
Metoda setError automatycznie resetuje się przy zmianie tekstu pola, jeśli włączona jest opcja setErrorEnabled(true). Takie zachowanie jest wygodne do walidacji w czasie rzeczywistym: gdy tylko użytkownik zacznie poprawiać błąd, czerwona ramka znika, a pole wraca do normalnego stanu. Jednak w złożonych scenariuszach to automatyczne resetowanie może być niepożądane — w takich przypadkach zarządzaj błędem ręcznie.
val til = findViewById<TextInputLayout>(R.id.til_email)
// Włącz obsługę błędów (ustaw w XML w przeciwnym razie)
til.isErrorEnabled = true
// Ustaw komunikat błędu
til.error = "Invalid email address"
// Wyczyść błąd
til.error = null
// Sprawdź, czy błąd istnieje
if (til.error != null) {
// Pole jest w stanie błędu
}
W przykładzie użyto właściwości Kotlin do dostępu do setError/isErrorEnabled. TextInputLayout automatycznie aktualizuje UI: zmienia kolor boxStrokeColor, pokazuje ikonę błędu, wyświetla tekst błędu. Jeśli zmienisz tekst w EditText, błąd jest resetowany automatycznie. Do ręcznego resetowania przypisz error = null.
Nie wszystkie projekty używają Material Design Components. Do niestandardowego wyświetlania błędu można użyć osobnego TextView pod EditText, który staje się widoczny przy błędzie. To podejście daje pełną kontrolę nad stylami i położeniem komunikatu. Można na przykład umieścić komunikat po prawej stronie pola, użyć innego koloru tła lub dodać ikonę po lewej stronie tekstu.
W Jetpack Compose Error State jest realizowany przez parametr isError w OutlinedTextField lub TextField. Przy isError = true ramka staje się czerwona i można pokazać tekst błędu przez supportingText. Compose nie ma wbudowanego auto-clear przy zmianie tekstu — programista zarządza stanem błędu ręcznie przez remember i mutableStateOf.
Do błędu grupowego (jeden komunikat dla kilku pól, np. „Wypełnij wszystkie wymagane pola”) używa się Snackbar, Dialog lub inline-bloku w górnej części formularza. Błąd grupowy nie zastępuje Error State poszczególnych pól, ale go uzupełnia. Użytkownik najpierw widzi ogólny komunikat, a następnie szuka konkretnych pól z błędami.
| Sposób | Zalety | Wady | Kiedy używać |
|---|---|---|---|
| TextInputLayout.setError | Standard, animacja, auto-clear | Tylko z Material Components | Główna opcja dla MDC |
| Osobny TextView | Pełna kontrola stylów | Trzeba zarządzać widocznością ręcznie | Niestandardowe motywy, bez MDC |
| Compose isError | Wbudowane w Compose | Ręczne zarządzanie stanem | Projekty na Jetpack Compose |
| Snackbar/Dialog | Komunikat grupowy | Nieprzypisane do konkretnego pola | Uzupełnienie Error State pola |
Kolor Error State w Material Design Components jest zarządzany przez atrybut boxStrokeErrorColor lub atrybut colorError w motywie. Domyślnie używany jest systemowy czerwony kolor, ale można go nadpisać w motywie aplikacji lub bezpośrednio w TextInputLayout przez app:boxStrokeErrorColor="@color/customErrorColor". Do obsługi ciemnego motywu zaleca się używanie selektora z różnymi kolorami dla trybu jasnego i ciemnego.
Ikona błędu jest konfigurowana przez app:errorIconDrawable. Domyślnie wyświetlany jest wykrzyknik w kole. Można go zastąpić niestandardową ikoną lub całkowicie usunąć, ustawiając app:errorIconDrawable="@null". Ikona jest wyświetlana na końcu TextInputLayout i służy jako dodatkowy znacznik wizualny. W Material Design 3 ikona błędu jest obowiązkowa dla dostępności.
Animacja pojawiania się błędu jest wbudowana w TextInputLayout: tekst wysuwa się od dołu z płynną zmianą przezroczystości. Do niestandardowej animacji użyj Transition API lub MotionLayout. Na przykład kołysanie pola przy błędzie przyciąga dodatkową uwagę. Jednak nadużywanie animacji pogarsza UX — wystarczy płynne pojawienie się komunikatu.
Zarządzanie Error State dzieli się na dwa etapy: ustawienie błędu przy walidacji pola i resetowanie błędu przy poprawieniu. W najprostszym przypadku walidacja jest wywoływana w TextWatcher.afterTextChanged: jeśli wartość jest nieprawidłowa, wywoływany jest setError z komunikatem o błędzie. Jeśli prawidłowa — setError(null). TextInputLayout automatycznie ukrywa błąd, gdy setError(null) resetuje stan.
Do walidacji formularza błędy są ustawiane na etapie wysyłania formularza. Przejście przez wszystkie pola, sprawdzenie każdego, ustawienie błędów dla nieprawidłowych pól i fokus na pierwszym błędnym polu. Przycisk wysyłania jest przy tym blokowany. Jeśli formularz jest duży, zaleca się przewinięcie ekranu do pierwszego pola z błędem i automatyczne ustawienie na nim fokusu.
Zasada single error focus: przy wysyłaniu formularza ustawiaj fokus tylko na pierwsze pole z błędem. Użytkownik poprawia jeden błąd na raz, a po poprawieniu następne pole z błędem automatycznie otrzymuje fokus. Takie podejście krok po kroku zmniejsza obciążenie poznawcze. Material TextInputLayout przy ustawianiu błędu nie przechwytuje fokusu — trzeba to zrobić ręcznie przez requestFocus().
Pierwszy błąd — brak isErrorEnabled. Jeśli setErrorEnabled nie został wywołany przed setError, układ może się przesunąć przy pojawieniu się komunikatu o błędzie. Szczególnie krytyczne, jeśli pole znajduje się w środku ekranu — użytkownik traci pozycję przewijania. Zawsze włączaj setErrorEnabled(true) w XML przez app:errorEnabled="true" lub programowo przed ustawieniem błędu.
Drugi błąd — zbyt długi komunikat o błędzie. Długi tekst zawija się do kilku wierszy i może zasłaniać sąsiednie pola. Zalecana długość komunikatu o błędzie to 20-40 znaków. Jeśli wymagane jest więcej informacji, użyj helperText (podpowiedź) w normalnym stanie lub tooltip do dodatkowego wyjaśnienia. Zwięzłość to podstawa dobrego Error State.
Trzeci błąd — ignorowanie dostępności. Error State musi być dostępny dla czytników ekranu. TextInputLayout automatycznie zapowiada błąd przez contentDescription, ale niestandardowe implementacje muszą to robić ręcznie. Używaj announceForAccessibility() lub android:importantForAccessibility dla komunikatów o błędzie. Użytkownicy TalkBack powinni słyszeć błąd natychmiast po jego pojawieniu się.
| Błąd | Problem | Rozwiązanie |
|---|---|---|
| Brak isErrorEnabled | Przesunięcie układu przy błędzie | app:errorEnabled="true" w XML |
| Długi komunikat | Zasłanianie sąsiednich pól | 20-40 znaków, helperText dla szczegółów |
| Brak dostępności | Czytnik ekranu nie słyszy błędu | Ważne dla użytkowników TalkBack |
| Auto-reset bez sprawdzenia | Pole błędnie uznawane za prawidłowe | Ręczne zarządzanie resetowaniem błędu |
Często zadawane pytania
Jeśli używasz TextInputLayout, wywołaj setError(null). Włącz setErrorEnabled(true), aby miejsce pod komunikatem pozostało zarezerwowane, ale tekst zniknął. Przy zmianie tekstu w EditText TextInputLayout automatycznie resetuje błąd. Do ręcznego zarządzania użyj addTextChangedListener i setError(null) przy każdej zmianie.
Ponieważ miejsce pod komunikat o błędzie nie jest zarezerwowane. Rozwiązanie: włącz app:errorEnabled="true" w XML dla TextInputLayout. To zarezerwuje miejsce pod komunikat i układ nie będzie się przesuwać. Jeśli błąd jest nieaktywny, miejsce pozostaje puste, ale układ jest stabilny.
Użyj atrybutu app:boxStrokeErrorColor w XML lub programowo przez til.setBoxStrokeErrorStateList(). Kolor można ustawić selektorem dla różnych stanów. Można również nadpisać systemowy atrybut colorError w motywie aplikacji, aby zmienić kolor błędu globalnie dla wszystkich pól.
Tak, użyj app:errorEnabled="true" i setError() — ale nadpisz boxStrokeErrorColor na główny kolor pola. Ikona i tekst błędu nadal będą widoczne, ale ramka pozostanie w oryginalnym kolorze. Jednak zmniejsza to widoczność błędu, co jest sprzeczne z zaleceniami Material Design dotyczącymi dostępności.
W Compose użyj isError = true w OutlinedTextField lub TextField. Tekst błędu przekazuje się przez parametr supportingText. Zarządzaj stanem przez mutableStateOf. Przy zmianie tekstu resetuj isError ręcznie. Compose nie ma auto-clear błędu, w przeciwieństwie do TextInputLayout w systemie View.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również