Układ siatki- kontrolka GridView
GridView to specjalna kontrolka w Androidzie, która umożliwia wyświetlanie wielu powtarzalnych elementów w układzie siatki w wierszach i kolumnach. Dzięki niej można w prosty sposób stworzyć np. galerię zdjęć, zestaw ikon podobny do pulpitu czy dynamiczne menu aplikacji. GridView samodzielnie dopasowuje liczbę kolumn do szerokości ekranu i pozwala przewijać zawartość, gdy elementów jest więcej niż mieści się na ekranie.

Każdy kafelek w siatce jest osobnym widokiem. Dlatego w praktyce stosuje się oddzielny layout XML dla pojedynczego elementu siatki. Takie podejście daje większą elastyczność pozwala łatwo zmieniać wygląd kafelka (np. dodawać obrazek, podpis, efekt zaznaczenia), a GridView automatycznie powiela ten układ dla wszystkich pozycji. Dzięki temu aplikacja jest bardziej przejrzysta, a kod łatwiejszy w utrzymaniu i rozbudowie.
Główny układ aplikacji z GridView
Aby przygotować aplikację z układem siatki, musimy zbudować główny layout aktywności. Layout ten odpowiada za rozmieszczenie wszystkich elementów interfejsu na ekranie. W naszym projekcie będzie to przede wszystkim kontrolka GridView, która wyświetli siatkę obrazów.
- W folderze res/layout otwórz plik activity_main.xml.
- Jako główny element layoutu umieść kontrolkę GridView.
- Ustaw jej parametry tak, aby automatycznie dopasowywała liczbę kolumn (numColumns="auto_fit") i szerokość kolumn (columnWidth).
- Dodaj odstępy (horizontalSpacing, verticalSpacing) i marginesy (padding), aby siatka była czytelna.
Ten układ będzie podstawą do niego podłączymy adapter w kodzie Kotlin, który wypełni siatkę obrazami.
Przykładowy układ siatki:
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<GridView
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:columnWidth="120dp"
android:verticalSpacing="8dp"
android:horizontalSpacing="8dp"
android:stretchMode="columnWidth"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Układ pojedynczego elementu (element_obraz.xml)
Każdy element wyświetlany w siatce GridView tworzony jest na podstawie oddzielnego pliku layoutu XML. Taki układ nazywamy item layout (u nas: element_obraz.xml) i służy do określenia wyglądu jednego kafelka w siatce (np. obrazek + podpis). Dzięki temu możemy łatwo zmieniać styl pojedynczego elementu, a zmiany automatycznie będą widoczne dla całej siatki.
- W folderze res/layout utwórz plik element_obraz.xml
- Wewnątrz umieść kontrolki, które mają być częścią kafelka (np. ImageView dla obrazka i TextView dla podpisu).
- Zadbaj o proporcje i sposób skalowania obrazów (scaleType="centerCrop", adjustViewBounds="true").
Ten layout będzie używany wielokrotnie przez adapter do tworzenia każdego kafelka w siatce.
Przykładowy układ pojedynczego elementu:
Wskazówka:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="160dp"
android:scaleType="centerCrop"
android:adjustViewBounds="true"/>
<TextView
android:id="@+id/textLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:paddingTop="4dp"/>
</LinearLayout>
Adapter do GridView
Sama kontrolka GridView odpowiada tylko za rozmieszczenie elementów w siatce. Aby wyświetlić konkretne dane (np. obrazy, podpisy), potrzebny jest adapter specjalna klasa, która łączy dane aplikacji z widokiem.
Adapter działa jak "most" między źródłem danych a GridView:
- Przechowuje listę elementów, które mają być pokazane (np. tablica identyfikatorów obrazów). Tworzy widok pojedynczego elementu na podstawie pliku element_obraz.xml.
- Wypełnia ten widok odpowiednimi danymi (np. ustawia obrazek i podpis).
- Oddaje gotowy widok do GridView, który umieszcza go w siatce.
W Androidzie często stosuje się własne klasy dziedziczące po BaseAdapter. Dzięki temu możemy dokładnie określić, jak wygląda i jak działa każdy kafelek w siatce.
Podsumowanie:
- GridView potrzebuje adaptera, aby wiedzieć co i jak ma wyświetlać.
- Adapter korzysta z layoutu element_obraz.xml, powielając go dla wszystkich elementów siatki.
- Dzięki adapterowi siatka jest dynamiczna i może obsługiwać dowolną liczbę danych.

Adapter obrazów
Cel klasy:
AdapterObrazow łączy dane (identyfikatory obrazów z res/drawable) z kontrolką GridView, tworząc dla każdego elementu widok typu ImageView.Przed utworzeniem klasy AdapterObrazow.kt do folderu res/ drawable skopiuj osiem dowolnych plików graficznych i nazwij je img1, img2 ? img8

W projekcie utwórz nowa klasę (język Kotlin) i nazwij ją AdapterObrazow

Napisz nagłówek:
Wskazówka:
class AdapterObrazow(private val context: Context) : BaseAdapter()
Android Studio podświetli na czerwono-użyj Alt+Enter \ Implement members.
Automatycznie wygeneruje wymagane metody:
- getCount()
- getItem()
- getItemId()
- getView()

Pełny kod utworzonej klasy
Wskazówka:
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ImageView
import android.widget.TextView
class AdapterObrazow(private val context: Context) : BaseAdapter() {
// Tablica z obrazami (muszą być w res/drawable)
private val images = arrayOf(
R.drawable.img1, R.drawable.img2, R.drawable.img3,
R.drawable.img4, R.drawable.img5, R.drawable.img6,
R.drawable.img7, R.drawable.img8
)
override fun getCount(): Int = images.size
override fun getItem(position: Int): Any = images[position]
override fun getItemId(position: Int): Long = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view: View
val holder: ViewHolder
if (convertView == null) {
view = LayoutInflater.from(context).inflate(R.layout.element_obraz,
parent, false)
holder = ViewHolder(
image = view.findViewById(R.id.imageView),
label = view.findViewById(R.id.textLabel)
)
view.tag = holder
} else {
view = convertView
holder = view.tag as ViewHolder
}
val imageResId = images[position]
holder.image.setImageResource(imageResId)
// Pobieramy nazwę pliku z zasobów
val resourceName = context.resources.getResourceEntryName(imageResId)
holder.label.text = resourceName
return view
}
//pomocnicza klasa dla uchwytu obrazów
//w której odwołujemy się do kontrolek ładowanego layotu
//pojedynczego elementu
private data class ViewHolder(
val image: ImageView,
val label: TextView
)
}
Jak to działa?:
- LayoutInflater.from(context).inflate(R.layout.element_obraz, parent, false) - wczytuje układ z element_obraz.xml (ImageView + TextView).
- getResourceEntryName(imageResId) - zwraca nazwę pliku z res/drawable (np. "img1").
- holder.label.text = resourceName - wyświetla tę nazwę pod obrazkiem.
Wywołanie adaptera
Otwórz plik MainActivity.kt. Zmiany w tym pliku obejmują:
Odniesienie do GridView
Wskazówka:
class MainActivity : AppCompatActivity() {
private lateinit var gridView: GridView
override fun onCreate(savedInstanceState: Bundle?) {
Utworzenie i przypisanie adaptera
Wskazówka:
//odwołanie do elemntu kontrolki siatki
gridView = findViewById(R.id.gridView)
val adapter = AdapterObrazow(this)
gridView.adapter = adapter
Obsługa kliknięcia elementu
Wskazówka:
gridView.onItemClickListener =
AdapterView.OnItemClickListener { _, _, id, _ ->
Toast.makeText(
this,
"Kliknięto obraz nr ${id + 1}",
Toast.LENGTH_SHORT
).show()
}
Pełny kod pliku ManActivity.kt
Wskazówka:
import android.os.Bundle
import android.widget.AdapterView
import android.widget.GridView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
private lateinit var gridView: GridView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
//odwołanie do elemntu kontrolki siatki
gridView = findViewById(R.id.gridView)
val adapter = AdapterObrazow(this)
gridView.adapter = adapter
gridView.onItemClickListener =
AdapterView.OnItemClickListener { _, _, id, _ ->
Toast.makeText(
this,
"Kliknięto obraz nr ${id + 1}",
Toast.LENGTH_SHORT
).show()
}
}
}
Skompiluj program i sprawdź efekt działania.

Podsumowanie: Układ siatki GridView
Kontrolka GridView, która umożliwia wyświetlanie wielu elementów w układzie siatki (wiersze i kolumny). Dzięki niej można łatwo tworzyć galerie obrazów, układy ikon czy dynamiczne menu.
Najważniejsze wnioski:
- GridView sam zajmuje się rozmieszczeniem kafelków, ale do wyświetlenia danych potrzebuje adaptera.
- AdapterObrazow odpowiada za powiązanie danych (lista obrazów) z widokiem dla każdego elementu nadmuchuje układ element_obraz.xml.
- W layoutcie pojedynczego elementu (element_obraz.xml) można umieścić nie tylko obraz, ale także tekst czy inne kontrolki.
- Funkcja getResourceEntryName() pozwala pobrać nazwę pliku zasobu i wyświetlić ją jako podpis pod obrazkiem.
- Dodając onItemClickListener, możemy reagować na wybór elementów siatki, np. wyświetlać komunikaty lub otwierać nowe ekrany.