EditText – pole tekstowe
Jak pobierać tekst wpisany przez użytkownika, ustawiać typ klawiatury, walidować dane oraz reagować na każdą zmianę tekstu w czasie rzeczywistym.
Czym jest EditText?
EditText to pole tekstowe w którym użytkownik może wpisywać tekst. To podstawowa kontrolka każdego formularza – logowania, rejestracji, wyszukiwania, wypełniania danych.
EditText dziedziczy po TextView, który z kolei dziedziczy po View. Oznacza to że wszystkie metody i atrybuty znane z TextView działają też na EditText – setText(), setTextColor(), setVisibility() i inne.
TextView
Tylko wyświetla tekst. Użytkownik nie może nic wpisać. Programista zmienia tekst przez setText().
EditText
Wyświetla tekst i pozwala użytkownikowi wpisywać. Programista odczytuje wpisany tekst przez getText().
Atrybuty XML
Podstawowe atrybuty
<EditText android:id="@+id/etImie" <!-- ID do odwołania w kodzie --> android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Wpisz imię" <!-- tekst podpowiedzi (szary, znika po kliknięciu) --> android:text="Jan" <!-- wartość domyślna (opcjonalne) --> android:inputType="textPersonName" <!-- typ klawiatury (opisane niżej) --> android:maxLength="30" <!-- maksymalna liczba znaków --> android:maxLines="1" <!-- ogranicz do jednej linii --> android:singleLine="true" <!-- Enter nie przechodzi do nowej linii --> android:textSize="16sp" android:padding="12dp" android:layout_marginBottom="12dp" />
android:hint to podpowiedź – szary tekst widoczny gdy pole jest puste, znika automatycznie gdy użytkownik zacznie pisać. android:text to tekst domyślny który pojawi się w polu od razu – użytkownik musi go ręcznie usunąć żeby wpisać coś innego. Na formularzach prawie zawsze używamy hint, nie text.
inputType – typ klawiatury
Atrybut android:inputType informuje Android jakiego typu dane będą wpisywane. Android na tej podstawie dobiera odpowiednią klawiaturę i może stosować dodatkowe formatowanie.
| Wartość inputType | Klawiat. która się pojawi | Kiedy używać |
|---|---|---|
text | Standardowa tekstowa | Dowolny tekst bez ograniczeń |
textPersonName | Tekstowa, wielka litera na starcie | Imię, nazwisko |
textEmailAddress | Tekstowa z widocznym @ | Adres e-mail |
textPassword | Tekstowa, znaki zastąpione kropkami | Hasło |
number | Numeryczna (tylko cyfry) | Liczba całkowita |
numberDecimal | Numeryczna z przecinkiem | Liczba z częścią dziesiętną |
numberPassword | Numeryczna, cyfry zastąpione kropkami | PIN |
phone | Numeryczna z +, *, # | Numer telefonu |
textMultiLine | Tekstowa z Enter przechodzącym do nowej linii | Notatka, wiadomość |
Ustawienie inputType="number" pokazuje klawiaturę numeryczną, ale nie gwarantuje że pole zawiera liczbę. Użytkownik może np. wkleić tekst ze schowka. Zawsze waliduj dane w kodzie przed ich użyciem.
Odczyt tekstu w kodzie
getText().toString()
Tekst wpisany przez użytkownika pobieramy metodą getText(). Zwraca ona obiekt typu Editable – dlatego zawsze dopisujemy .toString() żeby otrzymać zwykły String.
EditText etImie = findViewById(R.id.etImie); // getText() zwraca Editable – nie String! // Dlatego dodajemy .toString() aby dostać String String imie = etImie.getText().toString(); // Jeśli pole ma inputType="number" – konwertujemy na int EditText etWiek = findViewById(R.id.etWiek); int wiek = Integer.parseInt(etWiek.getText().toString()); // Jeśli pole ma inputType="numberDecimal" EditText etCena = findViewById(R.id.etCena); double cena = Double.parseDouble(etCena.getText().toString());
val etImie: EditText = findViewById(R.id.etImie) // Kotlin: .text zwraca Editable – .toString() konwertuje na String val imie = etImie.text.toString() // Konwersja na liczbę val wiek = etWiek.text.toString().toInt() val cena = etCena.text.toString().toDouble()
Wywołanie Integer.parseInt("") lub "".toInt() zakończy się wyjątkiem NumberFormatException i crashem aplikacji. Zanim spróbujesz skonwertować tekst na liczbę – zawsze sprawdź czy pole nie jest puste. Zobaczysz jak to zrobić w następnej sekcji.
Walidacja – sprawdzenie czy pole jest puste
Walidacja to sprawdzenie czy dane wpisane przez użytkownika są poprawne przed ich użyciem. Najprostszy i najczęstszy przypadek: czy pole nie jest puste.
String imie = etImie.getText().toString(); // trim() usuwa spacje z początku i końca – sam spacja to też "puste" pole if (imie.trim().isEmpty()) { // Pole jest puste – pokaż komunikat etImie.setError("To pole jest wymagane"); // czerwona ikonka błędu na polu return; // zatrzymaj wykonanie metody } else { // Pole ma tekst – możemy go bezpiecznie użyć tvWynik.setText("Witaj, " + imie); } // Walidacja liczby – sprawdź najpierw String, potem parsuj String wiekTekst = etWiek.getText().toString().trim(); if (wiekTekst.isEmpty()) { etWiek.setError("Podaj wiek"); return; } int wiek = Integer.parseInt(wiekTekst); // teraz bezpieczne
val imie = etImie.text.toString().trim() if (imie.isEmpty()) { etImie.setError("To pole jest wymagane") return } else { tvWynik.text = "Witaj, $imie" } // Walidacja liczby val wiekTekst = etWiek.text.toString().trim() if (wiekTekst.isEmpty()) { etWiek.setError("Podaj wiek") return } val wiek = wiekTekst.toInt() // teraz bezpieczne
Metoda setError("komunikat") wyświetla czerwoną ikonkę po prawej stronie pola EditText z dymkiem zawierającym podany tekst. To wbudowany mechanizm walidacji Androida – nie trzeba tworzyć osobnego TextView na komunikaty błędów. Wywołanie setError(null) usuwa błąd.
Operacje na EditText w kodzie
Ustawienie tekstu
Metoda setText() działa tak samo jak w TextView – bo EditText dziedziczy po TextView. Możesz wpisać tekst do pola programistycznie – np. aby wypełnić formularz domyślnymi wartościami.
// Wpisz tekst do pola etImie.setText("Jan Kowalski"); // Przesuń kursor na koniec tekstu etImie.setSelection(etImie.getText().length()); // Zaznacz cały tekst (przydatne żeby użytkownik od razu mógł zastąpić) etImie.selectAll();
etImie.setText("Jan Kowalski") // Przesuń kursor na koniec etImie.setSelection(etImie.text.length) // Zaznacz cały tekst etImie.selectAll()
Czyszczenie pola
Dwa równoważne sposoby wyczyszczenia zawartości pola – oba robią to samo:
// Sposób 1: setText z pustym Stringiem etImie.setText(""); // Sposób 2: getText().clear() – czyści obiekt Editable etImie.getText().clear(); // Po wyczyszczeniu można przywrócić fokus (kursor do pola) etImie.requestFocus();
// Sposób 1 etImie.setText("") // Sposób 2 etImie.text.clear() etImie.requestFocus()
Zmiana wyglądu w kodzie
Ponieważ EditText dziedziczy po TextView, wszystkie metody zmiany wyglądu działają identycznie:
// Aktywuj / dezaktywuj pole (false = szare, nieaktywne) etImie.setEnabled(false); etImie.setEnabled(true); // Zmień podpowiedź hint w kodzie etImie.setHint("Nowa podpowiedź"); // Zmień kolor tekstu etImie.setTextColor(Color.parseColor("#E6EDF3")); // Ukryj / pokaż (dziedziczone z View) etImie.setVisibility(View.GONE); etImie.setVisibility(View.VISIBLE); // Usuń komunikat błędu (po poprawnym wpisaniu) etImie.setError(null);
// Aktywuj / dezaktywuj pole etImie.isEnabled = false etImie.isEnabled = true // Zmień podpowiedź hint etImie.setHint("Nowa podpowiedź") // Ukryj / pokaż etImie.visibility = View.GONE etImie.visibility = View.VISIBLE // Usuń komunikat błędu etImie.setError(null)
Pełny przykład – formularz z walidacją
Łączymy wszystko razem: formularz z dwoma polami (imię i wiek), przycisk który pobiera dane, waliduje je i wyświetla wynik.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="24dp"> <EditText android:id="@+id/etImie" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Imię" android:inputType="textPersonName" android:maxLength="30" android:layout_marginBottom="12dp" /> <EditText android:id="@+id/etWiek" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Wiek" android:inputType="number" android:maxLength="3" android:layout_marginBottom="24dp" /> <Button android:id="@+id/btnZatwierdz" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Zatwierdź" android:layout_marginBottom="24dp" /> <TextView android:id="@+id/tvWynik" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Wynik pojawi się tutaj" android:textSize="18sp" android:gravity="center" android:padding="16dp" /> </LinearLayout>
public class MainActivity extends AppCompatActivity { EditText etImie, etWiek; Button btnZatwierdz; TextView tvWynik; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); } public void initUI() { etImie = findViewById(R.id.etImie); etWiek = findViewById(R.id.etWiek); btnZatwierdz = findViewById(R.id.btnZatwierdz); tvWynik = findViewById(R.id.tvWynik); btnZatwierdz.setOnClickListener(v -> { zatwierdz(); }); } public void zatwierdz() { String imie = etImie.getText().toString().trim(); String wiekTekst = etWiek.getText().toString().trim(); // Walidacja pola imię if (imie.isEmpty()) { etImie.setError("Podaj imię"); return; } // Walidacja pola wiek if (wiekTekst.isEmpty()) { etWiek.setError("Podaj wiek"); return; } // Bezpieczna konwersja – pole nie jest puste int wiek = Integer.parseInt(wiekTekst); // Usuń błędy jeśli były etImie.setError(null); etWiek.setError(null); // Wyświetl wynik tvWynik.setText("Imię: " + imie + ", Wiek: " + wiek); } }
class MainActivity : AppCompatActivity() { lateinit var etImie : EditText lateinit var etWiek : EditText lateinit var btnZatwierdz: Button lateinit var tvWynik : TextView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) initUI() } fun initUI() { etImie = findViewById(R.id.etImie) etWiek = findViewById(R.id.etWiek) btnZatwierdz = findViewById(R.id.btnZatwierdz) tvWynik = findViewById(R.id.tvWynik) btnZatwierdz.setOnClickListener { zatwierdz() } } fun zatwierdz() { val imie = etImie.text.toString().trim() val wiekTekst = etWiek.text.toString().trim() if (imie.isEmpty()) { etImie.setError("Podaj imię") return } if (wiekTekst.isEmpty()) { etWiek.setError("Podaj wiek") return } val wiek = wiekTekst.toInt() etImie.setError(null) etWiek.setError(null) tvWynik.text = "Imię: $imie, Wiek: $wiek" } }
TextWatcher – reagowanie na zmianę tekstu
Do tej pory reagowaliśmy na kliknięcie przycisku. TextWatcher pozwala reagować na każdą zmianę tekstu w polu EditText – na bieżąco, bez klikania przycisku. Przydatny do wyszukiwania w czasie rzeczywistym, liczenia znaków, bieżącej walidacji.
Interfejs TextWatcher wymaga implementacji trzech metod:
beforeTextChanged() – wywoływana przed zmianą (rzadko używana)
onTextChanged() – wywoływana w trakcie zmiany, otrzymuje nową zawartość
afterTextChanged() – wywoływana po zmianie, najczęściej używana
etImie.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Wywoływana PRZED zmianą – rzadko używana } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // s to aktualny tekst w polu po zmianie tvWynik.setText("Wpisujesz: " + s.toString()); } @Override public void afterTextChanged(Editable s) { // Najczęściej używana – s to Editable z aktualnym tekstem // Usuń błąd gdy użytkownik zacznie poprawiać if (!s.toString().trim().isEmpty()) { etImie.setError(null); } } });
etImie.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { // rzadko używana } override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { tvWynik.text = "Wpisujesz: ${s.toString()}" } override fun afterTextChanged(s: Editable?) { // Usuń błąd gdy użytkownik zacznie poprawiać if (!s.toString().trim().isEmpty()) { etImie.setError(null) } } })
Licznik znaków („120 znaków pozostało”), przycisk Zatwierdź aktywny dopiero gdy wszystkie pola są wypełnione, podpowiedzi przy wyszukiwaniu, walidacja hasła w czasie rzeczywistym (wymagana długość, duże litery). Wszystkie te przypadki wymagają TextWatcher – przycisk wyzwala akcję, ale nie aktualizuje UI na bieżąco.
Podsumowanie
| Operacja | Java | Kotlin |
|---|---|---|
| Odczytaj tekst | et.getText().toString() |
et.text.toString() |
| Odczytaj i usuń spacje | et.getText().toString().trim() |
et.text.toString().trim() |
| Sprawdź czy puste | tekst.isEmpty() |
tekst.isEmpty() |
| Konwersja na int | Integer.parseInt(tekst) |
tekst.toInt() |
| Konwersja na double | Double.parseDouble(tekst) |
tekst.toDouble() |
| Ustaw tekst | et.setText("tekst") |
et.setText("tekst") |
| Wyczyść pole | et.getText().clear() |
et.text.clear() |
| Pokaż błąd | et.setError("komunikat") |
et.setError("komunikat") |
| Usuń błąd | et.setError(null) |
et.setError(null) |
| Dezaktywuj pole | et.setEnabled(false) |
et.isEnabled = false |
| Nasłuch zmian tekstu | et.addTextChangedListener(new TextWatcher() { ... }) |
et.addTextChangedListener(object : TextWatcher { ... }) |
Zadanie dla uczniów
Kalkulator BMI
- Stwórz layout z dwoma polami
EditText: wzrost w cm (inputType:number) i waga w kg (inputType:numberDecimal) - Dodaj przycisk „Oblicz BMI” i pole
TextViewna wynik - Zadeklaruj wszystkie widoki jako pola klasy, zainicjalizuj w
initUI() - Przed obliczeniem sprawdź czy oba pola są wypełnione – użyj
setError()na pustych polach - Oblicz BMI:
waga / (wzrost_w_metrach * wzrost_w_metrach) - Wyświetl wynik w formacie: „BMI: 22.5 – prawidłowa masa ciała” (dodaj kategorię: <18.5 niedowaga, 18.5–24.9 norma, >24.9 nadwaga)
⭐ Bonus 1: zmień kolor tekstu wyniku w zależności od kategorii (zielony = norma, żółty = niedowaga, czerwony = nadwaga)
⭐⭐ Bonus 2: dodaj TextWatcher który aktywuje przycisk „Oblicz” dopiero gdy oba pola mają wartość (domyślnie przycisk setEnabled(false))
⭐⭐⭐ Bonus Kotlin: użyj ?.toDoubleOrNull() zamiast try-catch i obsłuż przypadek gdy konwersja nie powiedzie się