school-it.pl // android + kotlin // rozdział 6 // lekcja 20
Toast — komunikat wbudowany
Toast to krótki dymek na dole ekranu, który sam znika po kilku sekundach: „Zapisano”, „Skopiowano do schowka”, „Wysłano wiadomość”. Nie da się go kliknąć ani zamknąć — tylko informuje. W tej lekcji pokażesz Toast krótki i długi, z napisem z kodu i z zasobów, opanujesz „lawinę” Toastów i nauczysz się, kiedy Toast to zły wybór.
Czego się dziś nauczysz
- Pokażesz Toast z tekstem z kodu i z
strings.xml. - Wybierzesz czas wyświetlania: krótki lub długi.
- Zapamiętasz ostatni Toast i zastąpisz go nowym zamiast ustawiać w kolejce.
- Zdecydujesz, kiedy zamiast Toasta użyć błędu przy polu, napisu albo okna dialogowego.
- Poznasz ograniczenia Toastów w nowych wersjach Androida.
Jedna linia kodu
Toast nie potrzebuje żadnego wpisu w XML. Tworzysz go i pokazujesz w kodzie:
Toast.makeText(this, "Zapisano notatkę", Toast.LENGTH_SHORT).show()
| Fragment | Znaczenie |
|---|---|
Toast.makeText(…) | Tworzy komunikat — jeszcze go nie pokazuje. |
this | Kontekst: aktywność, z której pochodzi komunikat. |
"Zapisano notatkę" | Tekst — napis albo identyfikator zasobu: R.string.zapisano. |
Toast.LENGTH_SHORT | Czas wyświetlania. |
.show() | Pokazuje komunikat. Bez tego nic się nie stanie. |
this w listenerze
Wewnątrz setOnClickListener { … } słowo this nadal oznacza aktywność — Toast działa bez zmian. Wyjątkiem jest kod wewnątrz object : … (np. CountDownTimer z lekcji 15): tam this to ten obiekt, więc piszesz this@MainActivity.
Czas wyświetlania
| Stała | Czas | Kiedy |
|---|---|---|
Toast.LENGTH_SHORT | ok. 2 s | Krótkie potwierdzenie: „Zapisano”, „Skopiowano”. |
Toast.LENGTH_LONG | ok. 3,5 s | Dłuższy tekst, który trzeba przeczytać. |
Innych wartości nie ma — Toast.makeText(this, "…", 10000) nie da 10 sekund. Jeśli komunikat ma zostać na ekranie dłużej, to nie jest zadanie dla Toasta.
Lawina Toastów
Toasty ustawiają się w kolejce: gdy klikniesz przycisk dziesięć razy, zobaczysz dziesięć komunikatów, jeden po drugim, przez kilkanaście sekund. Rozwiązanie: zapamiętaj ostatni Toast w polu klasy i przed pokazaniem nowego anuluj stary:
private var ostatniToast: Toast? = null
private fun pokazToast(tekst: String) {
ostatniToast?.cancel() // usuń poprzedni, jeśli jest
ostatniToast = Toast.makeText(this, tekst, Toast.LENGTH_SHORT)
ostatniToast?.show()
}
Taka metoda pomocnicza ma jeszcze jedną zaletę: w całej klasie piszesz krótko pokazToast("Zapisano"), zamiast powtarzać długie Toast.makeText(…).show().
Kiedy Toast, a kiedy nie
Toast znika sam, nie da się go przeczytać ponownie i łatwo go przeoczyć. Dlatego nadaje się tylko do informacji, których przegapienie niczego nie psuje:
| Sytuacja | Najlepszy sposób |
|---|---|
| udana akcja: „Zapisano”, „Wysłano” | Toast |
| błąd w konkretnym polu formularza | EditText.error przy polu (lekcja 06) |
| wynik, który użytkownik ma widzieć | TextView na ekranie |
| usunięcie, które można cofnąć | Snackbar z przyciskiem „Cofnij” (lekcja 21) |
| pytanie: „Czy na pewno usunąć?” | AlertDialog (lekcja 22) |
Ograniczenia nowych Androidów
| Wersja | Co się zmieniło |
|---|---|
| Android 11 (API 30) | setGravity nie działa dla zwykłego Toasta tekstowego — nie przesuniesz go na środek ekranu. Toast zawsze jest na dole. |
| Android 12 (API 31) | Tekst Toasta ma najwyżej dwie linie, a obok pojawia się ikona aplikacji. |
W starszych materiałach zobaczysz toast.setGravity(Gravity.CENTER, 0, 0). Kompiluje się, ale na nowych telefonach nic nie zmienia. Własny wygląd Toasta i jego ograniczenia poznasz w lekcji 21.
Szybka notatka
Pole na notatkę i trzy przyciski. Zapisz pokazuje krótki Toast „Zapisano notatkę”; pusta notatka nie daje Toasta, tylko błąd przy polu. Statystyki pokazuje długi Toast z liczbą znaków i słów. Kopiuj kopiuje tekst do schowka i potwierdza to Toastem z strings.xml. Wszystkie Toasty idą przez metodę pokazToast, więc szybkie klikanie nie tworzy kolejki.
Przygotowanie projektu
- Nowy projekt Empty Views Activity, nazwa
SzybkaNotatka, Kotlin, API 24. - Dopisz tekst do
strings.xml, podmieńactivity_main.xmliMainActivity.kt.
<string name="skopiowano">Skopiowano do schowka</string>
<?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:orientation="vertical"
android:layout_margin="16dp"
android:fitsSystemWindows="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Szybka notatka"
android:textSize="24sp"
android:textStyle="bold" />
<EditText
android:id="@+id/etNotatka"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="top"
android:hint="Wpisz notatkę…"
android:inputType="textMultiLine|textCapSentences"
android:minLines="5" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/btnZapisz"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:text="Zapisz" />
<Button
android:id="@+id/btnStatystyki"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Statystyki" />
</LinearLayout>
<Button
android:id="@+id/btnKopiuj"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Kopiuj do schowka" />
</LinearLayout>
package pl.schoolit.szybkanotatka
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
// ---------- kontrolki ----------
private lateinit var etNotatka: EditText
private lateinit var btnZapisz: Button
private lateinit var btnStatystyki: Button
private lateinit var btnKopiuj: Button
// ---------- stan ----------
private var ostatniToast: Toast? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initUI()
ustawZdarzenia()
}
private fun initUI() {
etNotatka = findViewById(R.id.etNotatka)
btnZapisz = findViewById(R.id.btnZapisz)
btnStatystyki = findViewById(R.id.btnStatystyki)
btnKopiuj = findViewById(R.id.btnKopiuj)
}
private fun ustawZdarzenia() {
btnZapisz.setOnClickListener { zapisz() }
btnStatystyki.setOnClickListener { pokazStatystyki() }
btnKopiuj.setOnClickListener { kopiuj() }
}
// ---------- czynności ----------
private fun zapisz() {
val tekst = etNotatka.text.toString().trim()
if (tekst.isEmpty()) {
etNotatka.error = "Notatka jest pusta" // błąd w polu — nie Toast
return
}
pokazToast("Zapisano notatkę", Toast.LENGTH_SHORT)
}
private fun pokazStatystyki() {
val tekst = etNotatka.text.toString().trim()
val slowa = if (tekst.isEmpty()) 0 else tekst.split(Regex("\\s+")).size
pokazToast("Znaków: ${tekst.length}, słów: $slowa", Toast.LENGTH_LONG)
}
private fun kopiuj() {
val schowek = getSystemService(ClipboardManager::class.java)
schowek.setPrimaryClip(ClipData.newPlainText("notatka", etNotatka.text))
pokazToast(getString(R.string.skopiowano), Toast.LENGTH_SHORT)
}
// ---------- pomocnicze ----------
// najwyżej jeden Toast naraz: nowy zastępuje stary
private fun pokazToast(tekst: String, czas: Int) {
ostatniToast?.cancel()
ostatniToast = Toast.makeText(this, tekst, czas)
ostatniToast?.show()
}
}
Co dzieje się po kolei
- Kod ma układ z lekcji 19: pola, krótki
onCreate,initUI(),ustawZdarzenia()i metody czynności. - Pusta notatka to błąd danych, a nie informacja — dlatego
zapisz()pokazujeerrorprzy polu. Toast pojawia się tylko przy sukcesie. split(Regex("\\s+"))dzieli tekst w miejscach, gdzie jest jedna lub więcej spacji albo nowych linii — podwójna spacja nie tworzy „pustego słowa”.getSystemService(ClipboardManager::class.java)daje dostęp do schowka telefonu, aClipData.newPlainTexttworzy wpis z tekstem. Na Androidzie 13+ system sam pokazuje potwierdzenie kopiowania — nasz Toast jest dla starszych telefonów.getString(R.string.skopiowano)odczytuje tekst z zasobów, więc tłumaczenie aplikacji obejmie też komunikat.pokazToastanuluje poprzedni Toast, zanim pokaże nowy. Czas jest parametrem — metoda obsługuje oba rodzaje.
Sprawdź trzy rzeczy
- Kliknij Statystyki dziesięć razy szybko. Widać jeden Toast, który zmienia się od razu.
- W
pokazToastzakomentuj linięostatniToast?.cancel()i powtórz. Toasty ustawią się w kolejkę i będą się zmieniać jeszcze długo po ostatnim kliknięciu. - Usuń
.show()zpokazToast. Kod się skompiluje, ale żaden komunikat się nie pojawi.
Zestawienie elementów
| Element | Typ | Co robi |
|---|---|---|
Toast.makeText(kontekst, tekst, czas) | Toast | Tworzy komunikat. |
.show() | metoda | Pokazuje komunikat. |
.cancel() | metoda | Ukrywa komunikat lub usuwa go z kolejki. |
Toast.LENGTH_SHORT, Toast.LENGTH_LONG | stałe | Ok. 2 s i ok. 3,5 s. |
getString(R.string.…) | String | Tekst z zasobów. |
this@MainActivity | wyrażenie | Aktywność wewnątrz object : …. |
getSystemService(ClipboardManager::class.java) | usługa | Schowek systemowy. |
ClipData.newPlainText(etykieta, tekst) | ClipData | Wpis do schowka. |
tekst.split(Regex("\\s+")) | List | Podział na słowa po dowolnych odstępach. |
Zanim utkniesz
| Zapis / objaw | Problem |
|---|---|
| Toast się nie pokazuje | Brak .show() na końcu. |
Toast.makeText(this, punkty, …) z liczbą Int | Awaria Resources$NotFoundException: liczba jest traktowana jako identyfikator zasobu. Podaj napis: "Punkty: $punkty". |
Toast w CountDownTimer — błąd kompilacji przy this | W object : … this to ten obiekt. Pisz this@MainActivity. |
| Toasty pojawiają się jeszcze długo po kliknięciach | Kolejka. Anuluj poprzedni przez cancel(). |
setGravity(Gravity.CENTER, 0, 0) nic nie zmienia | Od Androida 11 nie działa dla Toastów tekstowych. |
| Toast z błędem formularza | Użytkownik nie wie, którego pola dotyczy, a komunikat znika. Błąd pokazuj przy polu. |
| długi tekst ucięty | Od Androida 12 najwyżej dwie linie. Skróć komunikat albo użyj okna dialogowego. |
Zadania
Każde zadanie wykonaj w nowym projekcie Empty Views Activity, w układzie z lekcji 19 (pola, initUI(), metody). Wskazówkę otwórz dopiero wtedy, gdy utkniesz.
Przyciski Krótki, Długi i Z zasobów. Pierwszy pokazuje Toast krótki, drugi długi, trzeci — tekst z strings.xml. Zmierz stoperem w telefonie, ile trwa każdy.
pokaż wskazówkę
Toast.makeTextprzyjmuje też identyfikator:Toast.makeText(this, R.string.powitanie, Toast.LENGTH_SHORT).
Przycisk Rzuć pokazuje wynik dużą cyfrą na ekranie, a przy wyrzuceniu szóstki dodatkowo Toast „Szóstka! Rzucasz jeszcze raz”. Szybkie klikanie nie może tworzyć kolejki Toastów.
pokaż wskazówkę
- Wynik zawsze w
TextView, a Toast tylko jako dodatek — skopiuj metodępokazToast.
Minutnik nauki: przycisk startuje 25-sekundowy CountDownTimer (udawane 25 minut). Co 5 sekund Toast „Zostało 20 minut” itd., a na koniec długi Toast „Czas na przerwę!”. Pasek postępu pokazuje upływ czasu.
pokaż wskazówkę
- W
onTickużyjthis@MainActivityalbo wywołaj metodę klasypokazToast— wtedy problem zthisznika sam.
Formularz rezerwacji stolika: imię, liczba osób (1–12), telefon. Przy kliknięciu Rezerwuj: błędy przy polach (nie Toasty), po sukcesie — Toast „Zarezerwowano stolik dla 4 osób” i podsumowanie w TextView, które zostaje na ekranie. Napisz w komentarzu na górze kodu, dlaczego podsumowanie nie może być tylko w Toaście.
pokaż wskazówkę
- Kieruj się tabelą „Kiedy Toast, a kiedy nie”.
Duży przycisk-licznik. Toast pojawia się tylko przy kamieniach milowych: 10, 25, 50, 100 („Masz już 25 kliknięć!”). Przy 100 długi Toast „Mistrz klikania!” i przycisk się blokuje. Kamienie milowe trzymaj w tablicy.
pokaż wskazówkę
- Sprawdzenie:
if (klikniecia in kamienie), gdziekamienie = intArrayOf(10, 25, 50, 100).
Weź przykład z lekcji i włącz na emulatorze TalkBack. Sprawdź, czy Toasty są czytane na głos i ile razy przy szybkim klikaniu. Potem zmień aplikację tak, aby oprócz Toasta ostatni komunikat był zawsze widoczny w małym napisie pod przyciskami (ustawianym w pokazToast). Opisz w trzech zdaniach w komentarzu, komu taki stały napis pomaga.
pokaż wskazówkę
- Pomyśl o osobach, które wolno czytają, mają słabszy wzrok albo odwróciły wzrok od ekranu w chwili pojawienia się Toasta.
Co trzeba zapamiętać
Toast.makeText(this, tekst, Toast.LENGTH_SHORT).show()— bezshow()nic się nie pojawi.- Są tylko dwa czasy:
LENGTH_SHORT(ok. 2 s) iLENGTH_LONG(ok. 3,5 s). - Ostatni Toast trzymaj w polu i anuluj przed pokazaniem nowego.
- Toast tylko do informacji, których przegapienie niczego nie psuje; błędy pokazuj przy polach, wyniki w
TextView. - Od Androida 11 Toast tekstowy jest zawsze na dole, od Androida 12 ma najwyżej dwie linie.
Dokumentacja: Toast, Toasty — przewodnik.