Android Studio · Kotlin INF.04

Układy w Androidzie

LinearLayout, ConstraintLayout, RelativeLayout i GridLayout – właściwości XML, konfiguracja i kiedy używać którego układu.

LinearLayout ConstraintLayout RelativeLayout GridLayout XML
01

Czym jest układ?

Układ (Layout) to niewidoczny kontener, który organizuje rozmieszczenie elementów interfejsu na ekranie. Sam nic nie wyświetla – mówi Androidowi gdzie i jak mają być ułożone jego dzieci (TextView, Button, ImageView itp.).

Układy można zagnieżdżać – LinearLayout może zawierać wewnątrz siebie ConstraintLayout, a ten z kolei inne widoki. Jednak głębokie zagnieżdżanie spowalnia renderowanie ekranu.

Układy = kontenery, widoki = treść

Każdy element w XML to albo układ (ViewGroup – ma dzieci) albo widok (View – nie ma dzieci). LinearLayout, ConstraintLayout, RelativeLayout, GridLayout to układy. TextView, Button, EditText, ImageView to widoki.

Właściwości wspólne dla wszystkich układów i widoków

Te atrybuty działają w każdym układzie i na każdym widoku – warto je znać na pamięć.

Atrybut XMLWartościOpis
android:layout_widthmatch_parent / wrap_content / XdpSzerokość elementu. match_parent = tyle co rodzic. wrap_content = tyle ile zajmuje treść. Xdp = stała liczba dp (np. 200dp).
android:layout_heightmatch_parent / wrap_content / XdpWysokość elementu. Takie same wartości jak layout_width.
android:id@+id/nazwaIdUnikalny identyfikator widoku. Wymagany gdy chcemy się do niego odwołać z kodu Kotlin przez findViewById().
android:paddingXdpWewnętrzny odstęp od krawędzi – między ramką a treścią. Można ustawić osobno: paddingTop, paddingBottom, paddingStart, paddingEnd.
android:layout_marginXdpZewnętrzny odstęp od sąsiednich elementów. Osobno: marginTop, marginBottom, marginStart, marginEnd.
android:background#RRGGBB / @color / @drawableKolor tła lub rysunek tła elementu.
android:visibilityvisible / invisible / gonevisible = widoczny. invisible = niewidoczny ale zajmuje miejsce. gone = niewidoczny i nie zajmuje miejsca.
android:alpha0.0 – 1.0Przezroczystość. 0 = całkowicie przezroczysty. 1 = nieprzezroczysty.
dp i sp – jednostki miar w Androidzie

dp (density-independent pixels) – jednostka do rozmiarów elementów. 1dp wygląda tak samo na każdym ekranie niezależnie od rozdzielczości.
sp (scale-independent pixels) – używana wyłącznie do rozmiarów tekstu (textSize). Respektuje ustawienia rozmiaru czcionki użytkownika.

02

LinearLayout

LinearLayout układa swoje dzieci w jednej linii – albo pionowo jeden pod drugim, albo poziomo obok siebie. To najprostszy układ – idealny do nauki i prostych ekranów.

Podgląd – LinearLayout vertical (lewo) i horizontal (prawo)
orientation=”vertical”
TextView
Button
EditText
orientation=”horizontal”
A
B
C

Właściwości LinearLayout

Atrybut XMLWartościOpis
android:orientationvertical / horizontalKierunek układania dzieci. vertical = jeden pod drugim. horizontal = obok siebie. Domyślnie: horizontal.
android:gravitycenter / top / bottom / start / end / center_horizontal / center_verticalWyrównanie wszystkich dzieci wewnątrz kontenera. np. gravity=”center” wyśrodkuje wszystkie elementy.
android:weightSumliczba całkowitaSuma wag dla layout_weight. Jeśli dzieci mają wagi 1, 2, 1 i weightSum=4 – proporcje są precyzyjne. Opcjonalne.
android:divider@drawable/liniaGraficzny separator między dziećmi. Wymaga też showDividers.
android:showDividersbeginning / middle / end / noneGdzie pokazywać separatory: przed, między lub po elementach.
android:baselineAlignedtrue / falseCzy wyrównać tekst dzieci po linii bazowej. Domyślnie true. Dla horizontal z różnymi rozmiarami tekstu.

layout_weight – proporcjonalne rozmiary

android:layout_weight to jedna z najważniejszych właściwości w LinearLayout. Pozwala rozdzielić dostępne miejsce proporcjonalnie między dzieci. Ustawiamy ją na dziecku, nie na kontenerze.

layout_weight – przykłady proporcji (horizontal)
weight=”1″ weight=”1″ weight=”1″ → równy podział
1
1
1
weight=”1″ weight=”2″ weight=”1″ → środek 2x szerszy
1
2
1
weight=”3″ weight=”1″ → lewy zajmuje 3/4
3
1
Atrybut XMLWartościOpis
android:layout_weightliczba (np. 1, 2, 0.5)Waga elementu – ile proporcjonalnego miejsca zajmie. Działą tylko w LinearLayout. Aby działało poprawnie ustaw layout_width=”0dp” (horizontal) lub layout_height=”0dp” (vertical).
android:layout_gravitycenter / top / bottom / start / end / fillWyrównanie tego konkretnego dziecka w osi prostopadłej do orientation. Różni się od gravity (które dotyczy wszystkich dzieci).
Ważne przy layout_weight

Gdy używasz layout_weight na elementach poziomego LinearLayout, ustaw android:layout_width="0dp". Gdy pionowego – android:layout_height="0dp". Wartość 0dp oznacza „Android sam obliczy rozmiar na podstawie wagi”.

gravity vs layout_gravity

android:gravity

Ustawiamy na kontenerze (LinearLayout). Określa jak rozmieszczone są wszystkie dzieci wewnątrz kontenera.

android:layout_gravity

Ustawiamy na dziecku. Określa jak to konkretne dziecko jest wyrównane w osi prostopadłej do orientation rodzica.

Przykład kompletny

res/layout/activity_main.xml XML
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"     <!-- pionowo, jeden pod drugim -->
    android:padding="16dp"
    android:gravity="center_horizontal" <!-- wszystkie dzieci wyśrodkowane poziomo -->
    android:background="#FAFAFA">

    <!-- Nagłówek -->
    <TextView
        android:id="@+id/tvTytul"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Logowanie"
        android:textSize="26sp"
        android:textStyle="bold"
        android:layout_marginBottom="24dp" />

    <!-- Pole tekstowe – pełna szerokość -->
    <EditText
        android:id="@+id/etLogin"
        android:layout_width="match_parent"  <!-- pełna szerokość rodzica -->
        android:layout_height="wrap_content"
        android:hint="Login"
        android:inputType="text"
        android:layout_marginBottom="12dp" />

    <EditText
        android:id="@+id/etHaslo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Hasło"
        android:inputType="textPassword"
        android:layout_marginBottom="20dp" />

    <!-- Rząd przycisków z wagami – każdy zajmuje połowę szerokości -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">

        <Button
            android:id="@+id/btnAnuluj"
            android:layout_width="0dp"     <!-- 0dp + weight = proporcjonalna szerokość -->
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Anuluj"
            android:layout_marginEnd="8dp" />

        <Button
            android:id="@+id/btnZaloguj"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:text="Zaloguj" />

    </LinearLayout>

</LinearLayout>
03

ConstraintLayout

ConstraintLayout pozycjonuje każdy widok przez wiązania (constraints) – połączenia krawędzi widoku z krawędzią innego widoku lub rodzica. To domyślny układ w nowych projektach Android Studio.

Każdy widok w ConstraintLayout musi mieć co najmniej dwa wiązania – jedno poziome i jedno pionowe. Bez nich Android nie wie gdzie umieścić element i umieszcza go w lewym górnym rogu.

xmlns:app – przestrzeń nazw ConstraintLayout

Właściwości ConstraintLayout zaczynają się od app: (nie android:). Dlatego w korzeniu layoutu musi być deklaracja: xmlns:app="http://schemas.android.com/apk/res-auto". Bez niej atrybuty app: nie będą działać.

Podgląd – ConstraintLayout z wiązaniami
Tytuł (top+start+end)
Przycisk (wyśrodkowany)
OK (bottom+end)

Właściwości ConstraintLayout

Każde wiązanie mówi: „moja krawędź X jest przyciągnięta do krawędzi Y obiektu Z”.

Atrybut XML (app:)WartościOpis
app:layout_constraintTop_toTopOfparent / @id/innyWidokGórna krawędź tego widoku przyciągnięta do górnej krawędzi rodzica lub innego widoku.
app:layout_constraintBottom_toBottomOfparent / @id/innyWidokDolna krawędź przyciągnięta do dolnej krawędzi celu.
app:layout_constraintStart_toStartOfparent / @id/innyWidokLewa krawędź przyciągnięta do lewej krawędzi celu.
app:layout_constraintEnd_toEndOfparent / @id/innyWidokPrawa krawędź przyciągnięta do prawej krawędzi celu.
app:layout_constraintTop_toBottomOf@id/innyWidokGórna krawędź przyciągnięta do dolnej krawędzi celu – element jest POD wskazanym widokiem.
app:layout_constraintBottom_toTopOf@id/innyWidokDolna krawędź przyciągnięta do górnej krawędzi celu – element jest NAD wskazanym widokiem.
app:layout_constraintStart_toEndOf@id/innyWidokLewa krawędź przyciągnięta do prawej krawędzi celu – element jest PO PRAWEJ wskazanego.
app:layout_constraintEnd_toStartOf@id/innyWidokPrawa krawędź przyciągnięta do lewej krawędzi celu – element jest PO LEWEJ wskazanego.

Bias – przesunięcie między wiązaniami

Gdy element ma wiązanie z obu stron jednocześnie (np. start i end do parent), Android domyślnie wyśrodkowuje go (bias = 0.5). Możemy to zmienić.

Atrybut XML (app:)WartościOpis
app:layout_constraintHorizontal_bias0.0 – 1.0Przesunięcie poziome. 0.0 = przy lewej krawędzi. 0.5 = wyśrodkowany. 1.0 = przy prawej krawędzi. Wymaga wiązań z obu stron (start i end).
app:layout_constraintVertical_bias0.0 – 1.0Przesunięcie pionowe. 0.0 = na górze. 0.5 = wyśrodkowany. 1.0 = na dole. Wymaga wiązań top i bottom.
Horizontal bias – porównanie wartości
bias=0.0
Widok
bias=0.3
Widok
bias=0.5
Widok
bias=1.0
Widok

Chain – łańcuch widoków

Gdy kilka widoków jest połączonych wiązaniami w obie strony między sobą, tworzą łańcuch (chain). Pierwszy element łańcucha jest jego „głową” i to na nim ustawiamy styl.

Atrybut XML (app:)WartościOpis
app:layout_constraintHorizontal_chainStylespread / spread_inside / packedStyl łańcucha poziomego. spread = elementy rozmieszczone równomiernie z marginesami. spread_inside = bez marginesów na krańcach. packed = elementy zebrane razem w centrum.
app:layout_constraintVertical_chainStylespread / spread_inside / packedStyl łańcucha pionowego – identyczne wartości co poziomy.

Przykład kompletny

res/layout/activity_main.xml XML
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"  <!-- wymagane! -->
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- Tytuł – wyśrodkowany poziomo, 32dp od góry -->
    <TextView
        android:id="@+id/tvTytul"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Profil użytkownika"
        android:textSize="22sp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent"    <!-- od góry rodzica -->
        app:layout_constraintStart_toStartOf="parent" <!-- od lewej rodzica -->
        app:layout_constraintEnd_toEndOf="parent"    <!-- i od prawej → wyśrodkowany -->
        android:layout_marginTop="32dp" />

    <!-- Pole tekstowe – POD tytułem, pełna szerokość z marginesami -->
    <EditText
        android:id="@+id/etImie"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Imię i nazwisko"
        app:layout_constraintTop_toBottomOf="@id/tvTytul" <!-- POD tvTytul -->
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="20dp"
        android:layout_marginStart="24dp"
        android:layout_marginEnd="24dp" />

    <!-- Przycisk – wyśrodkowany, lekko powyżej środka ekranu (bias=0.7) -->
    <Button
        android:id="@+id/btnZapisz"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Zapisz"
        app:layout_constraintTop_toBottomOf="@id/etImie"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="16dp" />

</androidx.constraintlayout.widget.ConstraintLayout>
04

RelativeLayout

RelativeLayout pozycjonuje elementy względem siebie nawzajem lub względem krawędzi rodzica. Jest prostszy od ConstraintLayout, ale mniej elastyczny. Dobry do layoutów gdzie elementy zależą od siebie pozycyjnie.

Podgląd – RelativeLayout z zależnościami między elementami
Nagłówek (alignParentTop)
Lewy (below nagłówek)
Prawy (toRightOf lewego)
Przycisk (alignParentBottom+End)

Właściwości RelativeLayout

Właściwości dzielą się na dwie grupy: względem rodzica (wartość true/false) i względem innego widoku (wartość @id/nazwaWidoku).

Atrybut XML (android:)WartościOpis
Względem rodzica (true/false)
android:layout_alignParentToptruePrzyciąga element do górnej krawędzi rodzica.
android:layout_alignParentBottomtruePrzyciąga element do dolnej krawędzi rodzica.
android:layout_alignParentStarttruePrzyciąga element do lewej krawędzi rodzica.
android:layout_alignParentEndtruePrzyciąga element do prawej krawędzi rodzica.
android:layout_centerInParenttrueWyśrodkowuje element poziomo i pionowo wewnątrz rodzica.
android:layout_centerHorizontaltrueWyśrodkowuje element tylko poziomo.
android:layout_centerVerticaltrueWyśrodkowuje element tylko pionowo.
Względem innego widoku (@id/…)
android:layout_below@id/innyWidokUmieszcza element poniżej wskazanego widoku.
android:layout_above@id/innyWidokUmieszcza element powyżej wskazanego widoku.
android:layout_toEndOf@id/innyWidokUmieszcza element po prawej stronie wskazanego widoku.
android:layout_toStartOf@id/innyWidokUmieszcza element po lewej stronie wskazanego widoku.
android:layout_alignTop@id/innyWidokWyrównuje górną krawędź do górnej krawędzi wskazanego widoku.
android:layout_alignBottom@id/innyWidokWyrównuje dolną krawędź do dolnej krawędzi wskazanego widoku.
android:layout_alignBaseline@id/innyWidokWyrównuje linię bazową tekstu do linii bazowej wskazanego widoku.

Przykład kompletny

res/layout/activity_main.xml XML
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <!-- Nagłówek – górna krawędź rodzica -->
    <TextView
        android:id="@+id/tvNaglowek"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Lista zadań"
        android:textSize="20sp"
        android:textStyle="bold"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true" />

    <!-- Przycisk dodaj – wyrównany do góry i prawej krawędzi rodzica -->
    <Button
        android:id="@+id/btnDodaj"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+ Dodaj"
        android:layout_alignParentTop="true"
        android:layout_alignParentEnd="true" />

    <!-- Pole tekstowe – poniżej nagłówka, po lewej stronie przycisku -->
    <EditText
        android:id="@+id/etZadanie"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Wpisz nowe zadanie..."
        android:layout_below="@id/tvNaglowek"      <!-- poniżej nagłówka -->
        android:layout_toStartOf="@id/btnDodaj"    <!-- po lewej stronie przycisku -->
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp" />

    <!-- Przycisk anuluj – dolna prawa krawędź ekranu -->
    <Button
        android:id="@+id/btnAnuluj"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Anuluj"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_marginBottom="16dp" />

</RelativeLayout>
05

GridLayout

GridLayout układa elementy w siatce wierszy i kolumn – jak tabela. Idealny do kalkulatorów, galerii, klawiatur numerycznych i wszelkich regularnych siatek elementów.

Podgląd – GridLayout 3 kolumny (kalkulator)
7
8
9
4
5
6
1
2
3
0
=

Właściwości GridLayout

Atrybut XML (android:)WartościOpis
Właściwości kontenera GridLayout
android:columnCountliczba całkowitaLiczba kolumn siatki. Np. columnCount=”3″ = trzy kolumny o równej szerokości.
android:rowCountliczba całkowitaLiczba wierszy siatki. Można pominąć – Android obliczy automatycznie.
android:orientationhorizontal / verticalKierunek wypełniania siatki. horizontal = lewo→prawo, potem następny wiersz. vertical = góra→dół, potem następna kolumna.
Właściwości dzieci GridLayout
android:layout_columnliczba (od 0)Numer kolumny gdzie umieścić element (indeksowanie od 0). Bez tego Android umieszcza automatycznie.
android:layout_rowliczba (od 0)Numer wiersza gdzie umieścić element (indeksowanie od 0).
android:layout_gravityfill / fill_horizontal / fill_vertical / center / start / endJak element wypełnia swoją komórkę. fill_horizontal rozciąga element na całą szerokość kolumny – ważne dla równych szerokości.

Łączenie komórek (Span)

Element może zajmować więcej niż jedną kolumnę lub wiersz – jak „merge cells” w Excelu.

Atrybut XML (android:)WartościOpis
android:layout_columnSpanliczba całkowitaIle kolumn zajmuje element. Np. columnSpan=”2″ = element rozciąga się na 2 kolumny. Zwykle łączymy z layout_gravity=”fill_horizontal”.
android:layout_rowSpanliczba całkowitaIle wierszy zajmuje element. Np. rowSpan=”2″ = element zajmuje 2 wiersze w pionie. Łączymy z layout_gravity=”fill_vertical”.

Przykład kompletny – kalkulator numeryczny

res/layout/activity_main.xml XML
<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="16dp">

    <!-- Ekran kalkulatora -->
    <TextView
        android:id="@+id/tvEkran"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:text="0"
        android:textSize="36sp"
        android:gravity="end|center_vertical"
        android:padding="8dp"
        android:background="#212121"
        android:textColor="#FFFFFF"
        android:layout_marginBottom="12dp" />

    <!-- Klawiatura numeryczna w siatce 3 kolumny -->
    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="3"             <!-- 3 kolumny -->
        android:rowCount="4"
        android:useDefaultMargins="true">

        <!-- Wiersz 1: 7, 8, 9 -->
        <Button android:text="7"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="8"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="9"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />

        <!-- Wiersz 2: 4, 5, 6 -->
        <Button android:text="4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="5"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="6"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />

        <!-- Wiersz 3: 1, 2, 3 -->
        <Button android:text="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />
        <Button android:text="3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />

        <!-- Wiersz 4: 0 (zajmuje 2 kolumny) i = -->
        <Button android:text="0"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1"
            android:layout_columnSpan="2" />  <!-- zajmuje 2 kolumny -->
        <Button android:text="="
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_columnWeight="1" />

    </GridLayout>
</LinearLayout>
06

Kiedy używać którego układu?

UkładKiedy używaćUnikaj gdy
LinearLayout Prosta lista elementów pionowo lub poziomo. Formularze. Paski przycisków. Gdy potrzebujesz wag (weight). Złożone pozycjonowanie. Nakładanie elementów. Duże zagnieżdżenia.
ConstraintLayout Złożone ekrany z wieloma widokami. Gdy chcesz uniknąć zagnieżdżania. Responsywne layouty na różne ekrany. Zalecany w nowych projektach. Bardzo proste ekrany z 2–3 elementami – LinearLayout będzie czytelniejszy.
RelativeLayout Elementy pozycjonowane względem siebie (np. przycisk zawsze obok pola tekstowego). Layouty z elementami przylepionymi do krawędzi. Nowe projekty – użyj ConstraintLayout. RelativeLayout jest starszy i mniej elastyczny.
GridLayout Kalkulatory. Klawiatury numeryczne. Galerie. Każdy układ regularnej siatki. Gdy potrzebujesz elementów zajmujących kilka kolumn/wierszy. Listy danych o zmiennej długości – użyj RecyclerView. Nieregularne układy.
Złota zasada zagnieżdżania

Nie zagnieżdżaj layoutów zbyt głęboko. Każdy poziom zagnieżdżenia spowalnia renderowanie. Zamiast 3 zagnieżdżonych LinearLayout – użyj jednego ConstraintLayout. Android musi „zmierzyć” każdy element dwukrotnie dla każdego poziomu zagnieżdżenia.

Layouty można mieszać

W praktyce często łączymy układy. Np. ConstraintLayout jako root z LinearLayout wewnątrz dla rzędu przycisków, a GridLayout dla klawiatury. Kluczowe pytanie: czy ten konkretny fragment najprościej opisać jako liniowy, siatkowy czy relatywny?

Zadanie

Zadanie – ćwiczenia z układami

Zadanie 1 – LinearLayout (formularz rejestracji)

  • Stwórz nowy projekt z Empty Views Activity, język Kotlin
  • Zmień layout na LinearLayout vertical z paddingiem 20dp
  • Dodaj TextView „Rejestracja” (textSize 24sp, bold, marginBottom 20dp)
  • Dodaj EditText na imię, nazwisko i e-mail (każdy match_parent, hint z opisem)
  • Na dole dodaj LinearLayout horizontal z dwoma przyciskami „Wyczyść” i „Zarejestruj” – każdy z wagą 1 i layout_width=”0dp”

Zadanie 2 – GridLayout (kalkulator)

  • Stwórz nową aktywność lub projekt
  • Na górze TextView jako ekran kalkulatora (textSize 36sp, gravity=end)
  • Pod nim GridLayout z 4 kolumnami: cyfry 0–9, operatory +−×÷, i przycisk = zajmujący 2 kolumny (columnSpan=”2″)
  • Użyj layout_columnWeight=”1″ dla równych szerokości przycisków

⭐ Bonus 1: w zadaniu 1 zastosuj ConstraintLayout zamiast LinearLayout – wyśrodkuj przycisk „Zarejestruj” poziomo (start+end do parent)

⭐⭐ Bonus 2: w zadaniu 2 obsłuż kliknięcia przycisków w Kotlinie – wyświetl klikniętą cyfrę na ekranie (TextView)

⭐⭐⭐ Bonus 3: użyj RelativeLayout – umieść przycisk „Wyczyść” zawsze w prawym dolnym rogu ekranu (alignParentBottom + alignParentEnd), a etykietę „Kalkulator” w lewym górnym rogu