Button i TextView
Jak umieścić przycisk i pole tekstowe w aplikacji Android, jak reagować na kliknięcie oraz jak za pomocą jednej metody obsłużyć wiele przycisków jednocześnie.
TextView i Button – czym są?
Widoki (widżety)
Wszystko co widzisz na ekranie aplikacji Android to widok (ang. view lub widget). Widoki to elementy interfejsu użytkownika umieszczane w plikach układu XML.
Dwa najczęściej używane widoki to TextView i Button. Oba są klasami języka Java/Kotlin, które dziedziczą po klasie bazowej View.
Klasa View pochodzi z pakietu android.view. Każdy widżet – Button, TextView, EditText, CheckBox – jest jej podklasą. Dlatego metody takie jak setVisibility() czy getId() działają na każdym z nich.
Najważniejsze atrybuty XML
Każdy widok definiujemy w pliku res/layout/activity_main.xml. Poniższa tabela pokazuje atrybuty, które będziesz używać najczęściej.
| Atrybut | Co robi | Przykład wartości |
|---|---|---|
android:id | Nadaje widokowi unikalną nazwę, przez którą odwołamy się do niego w kodzie | @+id/btnKliknij |
android:layout_width | Szerokość widoku | match_parent / wrap_content |
android:layout_height | Wysokość widoku | match_parent / wrap_content |
android:text | Tekst wyświetlany na widoku | "Kliknij mnie" |
android:textSize | Rozmiar czcionki – zawsze podajemy w sp | 20sp |
android:textColor | Kolor tekstu w notacji szesnastkowej | #FFFFFF |
android:gravity | Wyrównanie tekstu wewnątrz widoku | center |
android:padding | Wewnętrzny odstęp od krawędzi widoku | 16dp |
android:layout_margin | Zewnętrzny odstęp od sąsiednich widoków | 8dp |
android:onClick | Nazwa metody uruchamianej po kliknięciu (tylko Button) | "napiszCos" |
Rozmiar tekstu podajemy w sp (scale-independent pixels) – uwzględnia ustawienia wielkości czcionki w systemie telefonu. Marginesy i rozmiary widoków podajemy w dp (density-independent pixels). Nigdy nie używamy px.
Pierwsza aplikacja z przyciskiem
Zbudujemy prostą aplikację: użytkownik klika przycisk, a w polu tekstowym pojawia się napis. To klasyczny punkt startowy nauki Androida.
Krok 1 – Layout XML
W pliku res/layout/activity_main.xml umieszczamy dwa widoki: TextView do wyświetlania wyniku i Button do kliknięcia. Layout XML jest identyczny dla Java i Kotlin.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal" android:padding="24dp"> <!-- Pole tekstowe – początkowo puste, wypełni je kod --> <TextView android:id="@+id/tvWynik" <!-- ID do odwołania w kodzie --> android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Naciśnij przycisk..." android:textSize="22sp" android:gravity="center" android:padding="20dp" android:layout_marginBottom="32dp" /> <!-- Przycisk – android:onClick wskazuje metodę w Activity --> <Button android:id="@+id/btnKliknij" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Kliknij mnie!" android:textSize="16sp" android:onClick="napiszCos" <!-- nazwa metody w Activity --> android:paddingStart="32dp" android:paddingEnd="32dp" /> </LinearLayout>
Krok 2 – jak działa android:onClick?
Atrybut android:onClick="napiszCos" to umowa: „gdy użytkownik kliknie ten przycisk, wywołaj metodę o nazwie napiszCos w pliku aktywności”. Android sam przekazuje do tej metody parametr View v – referencję do przycisku który kliknięto.
Metoda przypisana przez android:onClick musi spełniać trzy warunki: być public, zwracać void i przyjmować dokładnie jeden parametr typu View. Inaczej aplikacja się nie skompiluje lub wyrzuci wyjątek w czasie działania.
Krok 3 – kod aktywności
W pliku aktywności tworzymy referencję do widoku TextView przez findViewById() i ustawiamy nowy tekst przez setText().
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Na razie nic tu nie dodajemy – metoda napiszCos jest niżej } // Ta metoda uruchomi się gdy użytkownik kliknie przycisk // Musi być: public, void, przyjmować View jako parametr public void napiszCos(View v) { // Szukamy widoku o id "tvWynik" w pliku układu TextView tekst = (TextView) findViewById(R.id.tvWynik); // Ustawiamy nowy napis tekst.setText("Przycisk został kliknięty!"); } }
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } // android:onClick działa tak samo jak w Java fun napiszCos(v: View) { val tekst = findViewById<TextView>(R.id.tvWynik) // Kotlin: właściwość .text zamiast setText() tekst.text = "Przycisk został kliknięty!" } }
W Kotlinie zamiast setText("...") piszemy .text = "...". Zamiast getText() piszemy .text. To nie są nowe metody – Kotlin automatycznie tłumaczy dostęp do właściwości na wywołanie gettera/settera.
Android podczas kompilacji czyta plik XML i dla każdego atrybutu android:id="@+id/cokolwiek" generuje stałą liczbową w klasie R. Dlatego R.id.tvWynik to po prostu liczba identyfikująca nasz widok. findViewById() przeszukuje aktywny układ i zwraca widok o podanym numerze.
Wiele przycisków – jedna wspólna metoda
W rzeczywistych aplikacjach mamy wiele przycisków. Zamiast pisać osobną metodę dla każdego z nich, możemy użyć jednej wspólnej metody, która sprawdza który przycisk został kliknięty.
Dlaczego jedna metoda jest lepsza?
❌ Osobna metoda dla każdego
Każdy przycisk ma swój android:onClick. Działa, ale gdy mamy 5 przycisków – piszemy 5 metod z podobnym kodem. Trudne w utrzymaniu.
✅ Jedna wspólna metoda
Wszystkie przyciski wskazują na tę samą metodę. Wewnątrz niej sprawdzamy który przycisk kliknięto. Kod w jednym miejscu, łatwy do zmiany.
Każda metoda onClick otrzymuje parametr View v – to referencja do widoku który kliknięto. Metoda v.getId() zwraca liczbowy identyfikator tego widoku. Porównując go z R.id.nazwaWidoku wiemy dokładnie który przycisk kliknął użytkownik.
Krok 1 – przypisanie tej samej metody w XML
Wszystkim przyciskom nadajemy tę samą nazwę w atrybucie android:onClick.
<LinearLayout ...orientation="vertical" android:padding="24dp"> <TextView android:id="@+id/tvWynik" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Wybierz działanie" android:textSize="24sp" android:gravity="center" android:padding="20dp" android:layout_marginBottom="24dp" /> <!-- Wszystkie trzy przyciski wskazują na TĘ SAMĄ metodę --> <Button android:id="@+id/btnDodaj" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Dodaj" android:onClick="kliknietoPrzycisk" /> <Button android:id="@+id/btnOdejmij" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Odejmij" android:onClick="kliknietoPrzycisk" /> <Button android:id="@+id/btnCzysc" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Wyczyść" android:onClick="kliknietoPrzycisk" /> </LinearLayout>
Krok 2 – jedna metoda z instrukcją switch
W metodzie kliknietoPrzycisk pobieramy id klikniętego widoku przez v.getId() i sprawdzamy który to przycisk instrukcją switch.
public class MainActivity extends AppCompatActivity { // Zmienna przechowuje aktualny wynik – zadeklarowana w klasie // aby była dostępna w każdej metodzie int wynik = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } // JEDNA metoda obsługuje TRZY przyciski public void kliknietoPrzycisk(View v) { // Pobieramy id klikniętego przycisku int id = v.getId(); // Sprawdzamy który przycisk kliknięto switch (id) { case R.id.btnDodaj: wynik = wynik + 1; break; case R.id.btnOdejmij: wynik = wynik - 1; break; case R.id.btnCzysc: wynik = 0; break; } // Aktualizujemy widok TextView TextView tvWynik = (TextView) findViewById(R.id.tvWynik); tvWynik.setText("Wynik: " + wynik); } }
class MainActivity : AppCompatActivity() { // Kotlin: var zamiast int (typ wywnioskowany) var wynik = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun kliknietoPrzycisk(v: View) { // Kotlin: when zamiast switch – czytelniejszy zapis when (v.id) { R.id.btnDodaj -> wynik++ R.id.btnOdejmij -> wynik-- R.id.btnCzysc -> wynik = 0 } val tvWynik = findViewById<TextView>(R.id.tvWynik) // String template: $wynik wstawia wartość zmiennej tvWynik.text = "Wynik: $wynik" } }
W Kotlinie switch zastępuje wyrażenie when. Jest bardziej czytelne – nie trzeba pisać break po każdej opcji. Zapis R.id.btnDodaj -> wynik++ to jeden wiersz zamiast czterech.
Gdyby wynik był deklarowany wewnątrz metody kliknietoPrzycisk(), resetowałby się do zera przy każdym kliknięciu. Deklarując go jako pole klasy (field) zachowuje wartość między kolejnymi wywołaniami metody.
Alternatywa: setOnClickListener w kodzie
Drugi sposób obsługi kliknięć to rejestracja nasłuchiwacza (listenera) bezpośrednio w kodzie Activity, bez użycia atrybutu android:onClick w XML.
To podejście jest używane gdy nie chcemy modyfikować pliku XML, albo gdy tworzymy widoki dynamicznie w kodzie (np. przyciski generowane w pętli).
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Pobieramy referencje do widoków TextView tvWynik = (TextView) findViewById(R.id.tvWynik); Button btnDodaj = (Button) findViewById(R.id.btnDodaj); Button btnOdejmij = (Button) findViewById(R.id.btnOdejmij); // Jedna lambda (listener) dla obu przycisków – ten sam trick z getId() View.OnClickListener listener = v -> { if (v.getId() == R.id.btnDodaj) wynik++; if (v.getId() == R.id.btnOdejmij) wynik--; tvWynik.setText("Wynik: " + wynik); }; btnDodaj.setOnClickListener(listener); btnOdejmij.setOnClickListener(listener); }
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val tvWynik = findViewById<TextView>(R.id.tvWynik) val btnDodaj = findViewById<Button>(R.id.btnDodaj) val btnOdejmij = findViewById<Button>(R.id.btnOdejmij) // Kotlin: zwarta lambda przypisana do zmiennej val listener = View.OnClickListener { v -> when (v.id) { R.id.btnDodaj -> wynik++ R.id.btnOdejmij -> wynik-- } tvWynik.text = "Wynik: $wynik" } btnDodaj.setOnClickListener(listener) btnOdejmij.setOnClickListener(listener) }
Kiedy co stosować?
| Metoda | Jak działa | Kiedy używać | Uwaga |
|---|---|---|---|
android:onClick w XML |
Nazwa metody wpisana w XML – Android sam ją wywołuje | Przyciski zdefiniowane w XML, prosta logika | Metoda musi być public void NazwaMetody(View v) |
Jedna metoda + switch(v.getId()) |
Wszystkie przyciski wskazują na tę samą metodę; switch rozróżnia który kliknięto | Wiele przycisków w jednym Activity – zalecane | Zmienna wynik musi być polem klasy, nie lokalną |
setOnClickListener w kodzie |
Listener rejestrujemy programistycznie w onCreate() |
Widoki tworzone dynamicznie; brak android:onClick w XML |
Nie wymaga modyfikacji XML – elastyczniejsze |
Na zajęciach i egzaminie najczęściej spotkasz metodę z android:onClick – to najprostsze i najbardziej czytelne podejście. Gdy masz wiele przycisków, przypisz im tę samą nazwę metody i użyj switch/when w środku. setOnClickListener wprowadź gdy opanujesz podstawy.
Podsumowanie pojęć
| Pojęcie | Java | Kotlin | Co robi? |
|---|---|---|---|
| Pobierz widok | (TextView) findViewById(R.id.x) |
findViewById<TextView>(R.id.x) |
Łączy zmienną z widokiem z XML |
| Ustaw tekst | tv.setText("napis") |
tv.text = "napis" |
Zmienia napis w TextView lub Button |
| Pobierz tekst | tv.getText().toString() |
tv.text.toString() |
Odczytuje aktualny napis z widoku |
| Id klikniętego | v.getId() |
v.id |
Zwraca liczbowy identyfikator widoku |
| Sprawdź który | switch(v.getId()) { case R.id.x: ... } |
when(v.id) { R.id.x -> ... } |
Rozgałęzienie na podstawie ID |
| Metoda kliknięcia | public void nazwa(View v) { } |
fun nazwa(v: View) { } |
Wymagana sygnatura dla android:onClick |
| String z liczbą | "Wynik: " + wynik |
"Wynik: $wynik" |
Składanie łańcucha z wartością zmiennej |
Zadanie dla uczniów
Prosta zgadywanka liczb
- Stwórz aplikację z
TextViewwyświetlającym pytanie: „Ile to 7 × 8?” - Dodaj trzy przyciski z odpowiedziami: 54, 56, 64
- Wszystkie trzy przyciski mają wskazywać na jedną wspólną metodę
sprawdzOdpowiedz - Wewnątrz metody użyj
switch(Java) lubwhen(Kotlin) zv.getId() - Po kliknięciu poprawnej odpowiedzi:
TextViewwyświetla „✅ Dobrze! 7 × 8 = 56″ - Po kliknięciu błędnej odpowiedzi: wyświetla „❌ Niepoprawnie, spróbuj jeszcze raz”
⭐ Bonus 1: zmień kolor tekstu w TextView – zielony dla poprawnej, czerwony dla błędnej odpowiedzi (setTextColor())
⭐⭐ Bonus 2: dodaj czwarty przycisk Reset, który przywraca pierwotne pytanie i neutralny kolor tekstu
⭐⭐⭐ Bonus Kotlin: cały kod przepisz w Kotlinie używając when, string templates ($zmienna) i właściwości zamiast setterów