school-it.pl // android + kotlin // rozdział 2 // lekcja 04
TextView — wyświetlanie tekstu
TextView to najczęściej używana kontrolka Androida — każdy napis, tytuł, wynik czy komunikat na ekranie to TextView. Znasz go już z poprzednich lekcji. Teraz poznasz go dokładnie: jak ustawić wygląd tekstu w XML, jak go zmieniać z kodu Kotlin i jak poradzić sobie z tekstem, który się nie mieści.
Czego się dziś nauczysz
- Ustawisz rozmiar, kolor, styl i krój tekstu w XML.
- Ograniczysz liczbę linii i dodasz wielokropek do zbyt długiego tekstu.
- Zmienisz tekst z kodu, także łącząc go z wartościami zmiennych.
- Zmienisz rozmiar i kolor tekstu z kodu.
- Wylosujesz element z tablicy i pokażesz go na ekranie.
Wygląd tekstu w XML
Wygląd napisu ustawiasz atrybutami w pliku układu. Najważniejsze:
| Atrybut | Przykładowa wartość | Efekt |
|---|---|---|
android:text | "@string/tytul" | Treść napisu. |
android:textSize | "20sp" | Rozmiar tekstu — zawsze w sp. |
android:textColor | "#C62828" lub "@color/akcent" | Kolor tekstu. |
android:textStyle | "bold", "italic", "bold|italic" | Pogrubienie, kursywa. |
android:fontFamily | "serif", "monospace", "sans-serif-light" | Krój pisma. |
android:textAllCaps | "true" | Wszystko wielkimi literami (tylko wyświetlanie). |
android:gravity | "center" | Wyrównanie tekstu w napisie (lekcja 02). |
android:lineSpacingExtra | "6dp" | Dodatkowy odstęp między liniami. |
android:letterSpacing | "0.1" | Odstęp między literami (ułamek wysokości litery). |
android:background | "#FFF3E0" | Tło napisu. |
Kolor w zapisie #RRGGBB
Po znaku # są trzy pary cyfr szesnastkowych: ilość czerwonego, zielonego i niebieskiego, od 00 do FF. #000000 to czarny, #FFFFFF biały, #FF0000 czerwony. Można dodać przezroczystość na początku: #80000000 to półprzezroczysta czerń. Kolor wybierzesz też myszką — kliknij mały kwadracik koloru na marginesie edytora XML.
Długi tekst
Gdy tekst jest dłuższy niż szerokość napisu, TextView sam zawija go do kolejnych linii. Czasem tego nie chcesz — na przykład w liście wiadomości, gdzie każdy wiersz ma mieć tę samą wysokość. Wtedy ograniczasz liczbę linii i każesz uciąć tekst wielokropkiem:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:ellipsize="end"
android:text="@string/dlugi_opis" />
wielokropek pokazuje użytkownikowi, że tekst jest dłuższy — sama treść w text się nie zmienia
ellipsize może mieć wartość end (wielokropek na końcu), start lub middle. Bez maxLines albo android:singleLine nie zadziała — tekst nie ma wtedy powodu, żeby się kończyć.
TextView w kodzie
Najpierw znajdujesz napis przez findViewById (lekcja 01), potem zmieniasz jego właściwości. Wszystko piszemy w onCreate, po setContentView:
val tvWynik = findViewById<TextView>(R.id.tvWynik)
val punkty = 42
tvWynik.text = "Masz $punkty punktów" // szablon napisu: $zmienna
tvWynik.append("\nGratulacje!") // dopisuje na końcu
tvWynik.textSize = 24f // rozmiar w sp, liczba z literą f
val ile = tvWynik.text.length // odczyt: długość tekstu
| Zapis | Znaczenie |
|---|---|
tv.text = "…" | Zastępuje cały tekst. |
"Masz $punkty pkt" | Szablon napisu: w miejsce $punkty wstawi się wartość zmiennej. |
"Razem: ${a + b}" | W klamrach może być całe wyrażenie — zostanie obliczone. |
tv.append("…") | Dopisuje tekst na końcu, nie kasując poprzedniego. |
tv.text.toString() | Odczyt tekstu jako zwykłego napisu String. |
tv.textSize = 24f | Ustawia rozmiar w sp. Litera f oznacza liczbę typu Float. |
textSize: zapis w sp, odczyt w pikselach
tvWynik.textSize = 24f ustawia 24 sp. Ale odczyt tvWynik.textSize zwraca rozmiar w prawdziwych pikselach ekranu — na typowym telefonie około trzy razy więcej. Zapis tvWynik.textSize = tvWynik.textSize + 2 nie powiększy więc tekstu o 2 sp, tylko kilkukrotnie. Rozmiar trzymaj we własnej zmiennej.
Kolory z kodu
Metoda setTextColor przyjmuje kolor jako liczbę. Taką liczbę dostaniesz na trzy sposoby:
tvWynik.setTextColor(Color.RED) // gotowa stała
tvWynik.setTextColor(Color.parseColor("#2E7D32")) // zapis #RRGGBB
tvWynik.setTextColor(getColor(R.color.akcent)) // kolor z colors.xml
tvWynik.setBackgroundColor(Color.parseColor("#FFF3E0")) // tło napisu
Color to klasa z pakietu android.graphics — wymaga linii import android.graphics.Color. Najlepszy jest trzeci sposób: kolor ma nazwę i jest w jednym miejscu, tak jak w XML (lekcja 02).
Nie podawaj numeru zasobu jako koloru
tvWynik.setTextColor(R.color.akcent) skompiluje się, ale tekst będzie miał dziwny, prawie przezroczysty kolor. R.color.akcent to numer zasobu, a nie kolor — zamienia go na kolor dopiero getColor(…).
Przysłowie dnia
Przy każdym uruchomieniu aplikacja losuje jedno przysłowie z tablicy i pokazuje je dużą, pochyłą czcionką, a pod spodem jego znaczenie. Krótkie przysłowia mają większą czcionkę niż długie. Na dole jest napis z numerem przysłowia, a jego kolor zależy od tego, czy numer jest parzysty.
uruchomienie
numer parzysty — zielona stopka, nieparzysty — czerwona
Przygotowanie projektu
- Nowy projekt Empty Views Activity, nazwa
PrzyslowieDnia, Kotlin, API 24. - Do
colors.xmldopisz kolorfiolet. Podmieństrings.xml,activity_main.xmliMainActivity.kt.
<color name="fiolet">#6750A4</color>
<resources>
<string name="app_name">Przysłowie dnia</string>
<string name="naglowek">Przysłowie dnia</string>
</resources>
<?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:letterSpacing="0.15"
android:text="@string/naglowek"
android:textAllCaps="true"
android:textColor="@color/fiolet"
android:textSize="14sp"
android:textStyle="bold" />
<!-- tekst wpisze kod; krój i styl ustawione tutaj -->
<TextView
android:id="@+id/tvPrzyslowie"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="serif"
android:textSize="30sp"
android:textStyle="italic" />
<TextView
android:id="@+id/tvZnaczenie"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:lineSpacingExtra="4dp"
android:textSize="16sp" />
<!-- pusty element z wagą spycha stopkę na dół ekranu (lekcja 02) -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/tvStopka"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14sp" />
</LinearLayout>
package pl.schoolit.przyslowiednia
import android.graphics.Color
import android.os.Bundle
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)
// 1. znajdujemy napisy
val tvPrzyslowie = findViewById<TextView>(R.id.tvPrzyslowie)
val tvZnaczenie = findViewById<TextView>(R.id.tvZnaczenie)
val tvStopka = findViewById<TextView>(R.id.tvStopka)
// 2. dane: dwie tablice tej samej długości
val przyslowia = arrayOf(
"Ćwiczenie czyni mistrza.",
"Nie od razu Kraków zbudowano.",
"Bez pracy nie ma kołaczy.",
"Kto pyta, nie błądzi.",
"Gdzie kucharek sześć, tam nie ma co jeść.",
"Lepiej późno niż wcale."
)
val znaczenia = arrayOf(
"Umiejętności zdobywa się przez powtarzanie.",
"Duże rzeczy wymagają czasu i cierpliwości.",
"Sukces wymaga wysiłku.",
"Lepiej zapytać, niż zgadywać i popełnić błąd.",
"Gdy za dużo osób zarządza jedną sprawą, nic się nie udaje.",
"Lepiej zrobić coś z opóźnieniem, niż nie zrobić wcale."
)
// 3. losujemy numer: od 0 do ostatniego indeksu
val nr = przyslowia.indices.random()
val przyslowie = przyslowia[nr]
// 4. tekst
tvPrzyslowie.text = "„$przyslowie”"
tvZnaczenie.text = znaczenia[nr]
tvStopka.text = "Przysłowie ${nr + 1} z ${przyslowia.size}"
tvStopka.append(" · uruchom ponownie, aby wylosować inne")
// 5. rozmiar zależny od długości tekstu
if (przyslowie.length > 30) {
tvPrzyslowie.textSize = 24f
}
// 6. kolor zależny od numeru (liczymy od 1, jak w stopce)
if ((nr + 1) % 2 == 0) {
tvStopka.setTextColor(Color.parseColor("#2E7D32"))
} else {
tvStopka.setTextColor(Color.parseColor("#C62828"))
}
}
}
Co dzieje się po kolei
- Wygląd przysłowia (krój
serif, kursywa, 30sp) jest ustawiony w XML. Kod wpisuje tylko tekst i — gdy trzeba — zmienia rozmiar. - Dwie tablice mają tyle samo elementów, a element nr 3 w jednej pasuje do elementu nr 3 w drugiej. Jeden wylosowany numer obsługuje obie.
przyslowia.indicesto zakres numerów tablicy (0..5), arandom()losuje z niego jedną liczbę.- Polskie cudzysłowy „ ” są zwykłymi znakami w napisie — dookoła wstawiamy wartość zmiennej przez
$przyslowie. - W stopce
${nr + 1}zamienia numer liczony od 0 na liczony od 1, zrozumiały dla człowieka.appenddopisuje drugą część. przyslowie.lengthto liczba znaków. Powyżej 30 zmniejszamy czcionkę do 24sp.- Reszta z dzielenia
% 2równa 0 oznacza liczbę parzystą.
Sprawdź trzy rzeczy
- Uruchom aplikację kilka razy (zamknij ją przyciskiem Wstecz i otwórz ikoną). Przysłowie się zmienia —
onCreatewykonuje się przy każdym otwarciu. - Na emulatorze otwórz Ustawienia → Wyświetlacz → Rozmiar czcionki i ustaw największy. Wszystkie napisy w aplikacji urosną, bo są w
sp. Stopka zostanie w jednej linii z wielokropkiem. - Zmień
tvPrzyslowie.textSize = 24fnatvPrzyslowie.textSize = tvPrzyslowie.textSize - 6. Długie przysłowie zrobi się olbrzymie — odczyt zwraca piksele, nie sp.
Zestawienie elementów
| Element | Typ | Co robi |
|---|---|---|
android:textSize, textColor, textStyle | atrybuty | Rozmiar, kolor, styl tekstu. |
android:fontFamily | atrybut | Krój: serif, monospace, sans-serif-light… |
android:maxLines + ellipsize | atrybuty | Ograniczenie linii i wielokropek. |
android:textAllCaps, letterSpacing, lineSpacingExtra | atrybuty | Wielkie litery, odstęp liter, odstęp linii. |
tv.text | właściwość | Odczyt i zmiana tekstu. |
tv.append("…") | metoda | Dopisuje tekst na końcu. |
tv.textSize = 20f | właściwość | Rozmiar: zapis w sp, odczyt w pikselach. |
tv.setTextColor(kolor) | metoda | Kolor tekstu. |
tv.setBackgroundColor(kolor) | metoda | Kolor tła. |
Color.RED, Color.parseColor("#…") | Int | Kolor jako liczba. |
getColor(R.color.…) | Int | Kolor z colors.xml. |
"$zmienna", "${wyrażenie}" | szablon | Wstawienie wartości do napisu. |
tablica.indices.random() | Int | Losowy poprawny numer elementu. |
napis.length | Int | Liczba znaków. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
tv.text = punkty (gdy punkty to Int) | Błąd kompilacji: Type mismatch. Tekst musi być napisem: "$punkty" albo punkty.toString(). |
tv.setText(punkty) z liczbą Int | Kompiluje się, ale aplikacja się zamyka (Resources$NotFoundException): liczbę Android traktuje jako numer zasobu tekstowego. |
tv.textSize = 20 | Błąd kompilacji: oczekiwany Float. Pisz 20f. |
tv.setTextColor(R.color.akcent) | Dziwny kolor. Potrzebne getColor(R.color.akcent). |
Color podświetlone na czerwono | Brak import android.graphics.Color — Alt+Enter. |
"Wynik: $a+b" | Wyświetli np. „Wynik: 3+b”. Wyrażenie musi być w klamrach: "${a + b}". |
ellipsize nie działa | Brak maxLines — tekst może się zawijać bez końca. |
przyslowia[przyslowia.size] | Awaria: ArrayIndexOutOfBoundsException. Ostatni indeks to size - 1. |
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.
Ekran z dziesięcioma napisami „Android”, każdy z innym ustawieniem: rozmiar 12sp i 36sp, pogrubienie, kursywa, pogrubienie z kursywą, krój serif, krój monospace, kolor czerwony, białe litery na czarnym tle, odstęp liter 0.3. Wszystko w XML, bez kodu.
pokaż wskazówkę
- Pogrubienie z kursywą:
android:textStyle="bold|italic".
W kodzie zadeklaruj zmienne imie, nazwisko, rokUrodzenia. Na ekranie mają się pojawić trzy napisy: „Anna Nowak”, „Rok urodzenia: 2009”, „Wiek w tym roku: 17”. Wiek oblicz w kodzie (rok bieżący wpisz na stałe).
pokaż wskazówkę
"Wiek w tym roku: ${2026 - rokUrodzenia}"— obliczenie w klamrach.
Pięć „wiadomości” jedna pod drugą: każda ma pogrubiony tytuł w jednej linii i treść ograniczoną do dwóch linii z wielokropkiem. Teksty niech będą na tyle długie, żeby wielokropek było widać.
pokaż wskazówkę
- Tytuł:
maxLines="1"+ellipsize="end". Treść:maxLines="2"+ellipsize="end".
Aplikacja losuje ocenę od 1 do 6 i pokazuje ją bardzo dużą cyfrą (96sp) na środku ekranu, a pod nią słownie („celujący”, „bardzo dobry”…). Kolor cyfry: 1 — czerwony, 2–3 — pomarańczowy, 4–5 — niebieski, 6 — zielony. Kolory zdefiniuj w colors.xml.
pokaż wskazówkę
- Losowanie:
(1..6).random(). Wybór koloru i słowa wygodnie zrobić instrukcjąwhen (ocena) { 1 -> … 2, 3 -> … }. Kolor z zasobów:getColor(R.color.zielony).
Jeden TextView z czcionką monospace. Kod w pętli dopisuje do niego tabliczkę mnożenia przez losową liczbę od 2 do 9: „7 x 1 = 7”, „7 x 2 = 14”… do 10, każda w osobnej linii. Nad nią nagłówek „Tabliczka mnożenia przez 7”.
pokaż wskazówkę
- Najpierw
tv.text = "", potem w pętlifor (i in 1..10)wywołujtv.append("$liczba x $i = ${liczba * i}\n").
W kodzie jest długi napis — na przykład pierwszy akapit dowolnego opowiadania (wpisz go sam). Aplikacja pokazuje: cały tekst w napisie z przewijaniem (ScrollView z lekcji 03), a pod nim statystyki: liczbę znaków, liczbę słów, liczbę samogłosek i najdłuższe słowo. Liczba samogłosek ma kolor zielony, gdy stanowi więcej niż 35% znaków, w przeciwnym razie czerwony.
pokaż wskazówkę
- Słowa:
tekst.split(" "). Samogłoski:tekst.count { it.lowercaseChar() in "aąeęioóuy" }. Najdłuższe słowo:slowa.maxBy { it.length }.
Co trzeba zapamiętać
- Wygląd napisu ustawiaj w XML:
textSize(sp),textColor,textStyle,fontFamily. - Zbyt długi tekst utnij parą
maxLines+ellipsize="end". - W kodzie:
tv.text = "Wynik: $x",tv.append(…),tv.textSize = 20f. - Kolor z kodu:
setTextColor(Color.parseColor("#…"))lubsetTextColor(getColor(R.color.…))— nigdy samoR.color.…. - Do
textprzypisuj napis, nie liczbę.
Dokumentacja: TextView, Szablony napisów w Kotlinie.