Matrix w Androidzie: co to jest, typy macierzy i praca z transformacjami

Autor: IT Sectr Opublikowano: 2026-07-22 Czas czytania: 9 min

Matrix — to klasa z Android SDK (android.graphics.Matrix), reprezentująca przekształcenie afiniczne poprzez macierz 3×3. Jest używana do transformacji obiektów graficznych — przesuwania, skalowania, obracania i pochylania. Według Android Developers Documentation (2026), Matrix jest podstawowym narzędziem do pracy z transformacjami w Canvas, Bitmap i Drawable, zapewniając precyzyjne zarządzanie współrzędnymi przy niestandardowym rysowaniu.

Najważniejsze

  • Matrix — klasa Androida do przekształceń afinicznych i perspektywicznych z macierzą 3×3
  • Operacje afiniczne: translate (przesunięcie), scale (skalowanie), rotate (obrót) i skew (pochylenie)
  • Matrix obsługuje przekształcenia perspektywiczne (projective) poprzez setPolyToPoly
  • Kolejność stosowania operacji jest ważna — Matrix.concat wykonuje sekwencyjne mnożenie
  • Matrix jest stosowana do Canvas, Bitmap, RectF, PointF i Path w grafice Androida

Czym jest Matrix w Androidzie?

Matrix (android.graphics.Matrix) — to klasa Android SDK, reprezentująca macierz matematyczną 3×3, używaną do transformacji dwuwymiarowych współrzędnych. Matrix jest podstawowym elementem konstrukcyjnym dla wszystkich przekształceń graficznych w Androidzie — od przesuwania i skalowania Canvas po złożone perspektywiczne zniekształcenia Bitmap.

W przeciwieństwie do iOS, gdzie używane są oddzielne struktury CGAffineTransform (afiniczne) i CATransform3D (3D), Android łączy przekształcenia afiniczne i perspektywiczne w jednej klasie Matrix. Macierz 3×3 pozwala reprezentować zarówno standardowe operacje afiniczne (ostatni wiersz [0, 0, 1]), jak i perspektywiczne zniekształcenia, gdy ostatni wiersz zawiera dowolne wartości. Daje to więcej elastyczności, ale wymaga zrozumienia matematyki macierzy.

Matrix jest ściśle zintegrowany z Canvas API. Gdy programista wywołuje canvas.translate(), canvas.scale() lub canvas.rotate(), te metody wewnętrznie modyfikują macierz kontekstu graficznego. Bieżącą macierz Canvas można uzyskać przez canvas.getMatrix(), a ręcznie zastosować niestandardową — przez canvas.setMatrix() lub canvas.concat().

Rodzaje przekształceń Matrix

Matrix obsługuje cztery podstawowe typy przekształceń afinicznych: translate, scale, rotate, skew (pochylenie). Każdy typ ma metody dla pre-mnożenia (pre), post-mnożenia (post) i ustawiania (set). Różnica między preTranslate a postTranslate polega na kolejności mnożenia macierzy, co wpływa na końcowe przekształcenie przy łączeniu.

OperacjaMetodaParametryOpis
TranslatesetTranslate / preTranslate / postTranslatedx, dyPrzesunięcie wzdłuż osi X i Y
ScalesetScale / preScale / postScalesx, sy, px, pySkalowanie z punktem odniesienia
RotatesetRotate / preRotate / postRotatedegrees, px, pyObrót wokół punktu odniesienia
SkewsetSkew / preSkew / postSkewkx, kyPochylenie (przesunięcie) wzdłuż osi

Translate — przesunięcie

Translate zmienia położenie wszystkich punktów o zadane przesunięcie dx, dy. Dodatnie dx przesuwa w prawo, dy — w dół (w układzie współrzędnych ekranu Androida oś Y skierowana jest w dół). Translate nie zmienia kształtu obiektu — tylko jego pozycję. To najprostsza i najczęściej używana operacja do pozycjonowania elementów.

Scale — skalowanie

Scale zmienia rozmiar obiektu ze współczynnikami sx (wzdłuż X) i sy (wzdłuż Y). Parametry px, py określają punkt odniesienia skalowania (pivot point). Jeśli px, py nie są podane, skalowanie wykonywane jest względem początku układu współrzędnych (0, 0). Przy sx = sy obiekt skalowany jest równomiernie. Ujemne wartości tworzą odbicie.

Rotate — obrót

Rotate obraca obiekt o zadany kąt (w stopniach) wokół punktu odniesienia (px, py). Dodatnia wartość stopni odpowiada obrotowi zgodnie z ruchem wskazówek zegara (w przeciwieństwie do iOS/macOS, gdzie dodatni kąt oznacza obrót przeciwny do ruchu wskazówek zegara). Jeśli px, py nie są podane, obrót wykonywany jest wokół początku układu współrzędnych.

Skew — pochylenie

Skew (przesunięcie) deformuje obiekt, pochylając go wzdłuż osi X (kx) lub osi Y (ky). Wartość 1.0 pochyla o 45 stopni. Skew jest używany do tworzenia efektów pochylenia, imitacji trójwymiarowego widoku (pseudo-3D) i zniekształceń perspektywy.

Struktura macierzy 3×3

Matrix przechowuje elementy macierzy 3×3 w wewnętrznej tablicy 9 wartości zmiennoprzecinkowych (float[9]). Kolejność przechowywania — column-major (wg kolumn), co odpowiada standardowemu matematycznemu przedstawieniu. Dostęp do poszczególnych elementów odbywa się poprzez stałe: Matrix.MSCALE_X, Matrix.MSKEW_Y, Matrix.MTRANS_X i tak dalej.

Elementy macierzy

Macierz jest zorganizowana następująco: pierwsze dwie kolumny (MSCALE_X, MSKEW_X, MSKEW_Y, MSCALE_Y) odpowiadają za skalowanie, obrót i pochylenie. Trzecia kolumna (MTRANS_X, MTRANS_Y, MPERSP_2) — za przesunięcie i perspektywę. Dla przekształcenia afinicznego MPERSP_0 i MPERSP_1 są równe 0, a MPERSP_2 jest równy 1.

Do pobierania wartości macierzy używane jest getValues(float[] values), które wypełnia tablicę 9 elementów. Do ustawiania — setValues(float[] values). Pozwala to manipulować macierzą bezpośrednio dla złożonych niestandardowych przekształceń wykraczających poza standardowe metody translate, scale, rotate i skew.

Sprawdzanie typu macierzy

Matrix udostępnia kilka metod do klasyfikacji bieżącego stanu. isIdentity() sprawdza, czy macierz jest jednostkowa. isAffine() — czy zawiera tylko przekształcenia afiniczne (MPERSP_0 = 0, MPERSP_1 = 0, MPERSP_2 = 1). Te sprawdzenia są przydatne do optymalizacji: jeśli macierz jest jednostkowa, transformację można pominąć.

Podstawowe operacje z Matrix

Matrix obsługuje kilka kategorii operacji: ustawianie (set), pre-mnożenie (pre), post-mnożenie (post), konkatenacja (concat), inwersja (invert) i mapowanie (map). Każda kategoria rozwiązuje swoje zadanie przy budowaniu złożonych przekształceń.

Operacje Pre i Post

preTranslate mnoży bieżącą macierz z lewej strony przez macierz przesunięcia: result = translate × current. postTranslate mnoży z prawej strony: result = current × translate. Różnica polega na kolejności stosowania: pre-operacje są stosowane przed bieżącymi transformacjami, post-operacje — po. Analogicznie działają preScale, postScale, preRotate, postRotate oraz preSkew, postSkew.

Inwersja i konkatenacja

invert(Matrix inverse) oblicza macierz odwrotną. Jeśli macierz źródłowa jest zdegenerowana (wyznacznik równy zero), zwracana jest wartość false. concat(Matrix other) mnoży bieżącą macierz przez przekazaną: set = set × other. Dla odwrotnej kolejności użyj setConcat(other, this).

Map — zastosowanie do punktów i prostokątów

mapRect(RectF rect) przekształca prostokąt i zwraca wynik w nowym RectF. mapPoints(float[] dst, float[] src) przekształca tablicę punktów. mapVectors(float[] dst, float[] src) przekształca wektory — bez uwzględniania przesunięcia (translate). mapRect jest przydatny do obliczania bounding box po transformacji.

Zastosowanie w Canvas i Bitmap

Matrix jest aktywnie używana w dwóch kluczowych scenariuszach grafiki Androida: transformacja Canvas i transformacja Bitmap. W obu przypadkach Matrix określa, jak dokładnie zostanie zmieniony wynik graficzny.

Transformacja Canvas przez Matrix

Canvas udostępnia metody canvas.setMatrix(matrix) do całkowitej wymiany bieżącej macierzy i canvas.concat(matrix) do mnożenia bieżącego przekształcenia przez przekazane. Po zastosowaniu Matrix całe kolejne rysowanie — wywołania drawBitmap, drawRect, drawPath — jest wykonywane w przekształconym układzie współrzędnych. Canvas przechowuje również własny stos zapisanych stanów poprzez save() i restore().

Transformacja Bitmap przez Matrix

Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) tworzy nową Bitmap z zastosowaniem zadanego przekształcenia. To potężne narzędzie do tworzenia przeskalowanych, obróconych lub zniekształconych kopii obrazów bez utraty oryginalnej Bitmap. Parametr filter kontroluje wygładzanie przy interpolacji pikseli.

setPolyToPoly — przekształcenia perspektywiczne

setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — unikalna funkcja Matrix, niemająca bezpośrednich odpowiedników w CGAffineTransform. Oblicza macierz przekształcającą zadane punkty z jednego wielokąta w drugi. Przy pointCount = 4 tworzy pełne przekształcenie perspektywiczne (projective), pozwalające nakładać Bitmap ze zniekształceniem perspektywy.

Przykłady kodu w Kotlin

Rozważmy praktyczne przykłady użycia Matrix do transformacji grafiki w aplikacji Androida w Kotlin.

Podstawowe przekształcenia afiniczne

Przykład tworzy Matrix dla połączonego przekształcenia: przesunięcie o (100, 50), skalowanie 1.5 raza i obrót o 45 stopni. Użycie postTranslate po preRotate i preScale zmienia kolejność stosowania operacji.

kotlin
val matrix = Matrix()
matrix.preScale(1.5f, 1.5f)
matrix.preRotate(45f)
matrix.postTranslate(100f, 50f)

// Zastosowanie do punktów
val pts = floatArrayOf(0f, 0f, 100f, 100f)
matrix.mapPoints(pts)

// Zastosowanie do prostokąta
val rect = RectF(0f, 0f, 200f, 100f)
matrix.mapRect(rect)

Transformacja Canvas z save i restore

Przykład demonstruje zastosowanie Matrix do Canvas w onDraw do obracania i skalowania koła wokół jego środka. Zapisywanie i przywracanie stanu Canvas gwarantuje, że transformacja nie wpłynie na kolejne elementy rysowania.

kotlin
override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)

    val cx = width / 2f
    val cy = height / 2f
    val radius = 100f

    canvas.save()
    val matrix = Matrix()
    matrix.postTranslate(cx, cy)
    matrix.postRotate(30f)
    matrix.postScale(1.2f, 1.2f)
    canvas.concat(matrix)

    val paint = Paint().apply {
        color = Color.BLUE
        style = Paint.Style.FILL
    }
    canvas.drawCircle(0f, 0f, radius, paint)
    canvas.restore()
}

Zniekształcenie perspektywiczne przez setPolyToPoly

Przykład używa setPolyToPoly do stworzenia perspektywicznego zniekształcenia Bitmap. Cztery punkty źródłowe (narożniki oryginalnego prostokąta) są mapowane na cztery punkty docelowe, tworzące trapez. Rezultat — efekt obrazu nachylonego w przestrzeni.

kotlin
fun applyPerspective(
    bitmap: Bitmap,
    skew: Float
): Bitmap {
    val w = bitmap.width.toFloat()
    val h = bitmap.height.toFloat()

    val src = floatArrayOf(0f, 0f, w, 0f,
                         0f, h, w, h)
    val dst = floatArrayOf(skew, 0f, w - skew, 0f,
                         0f, h, w, h)

    val matrix = Matrix()
    matrix.setPolyToPoly(src, 0, dst, 0, 4)

    return Bitmap.createBitmap(
        bitmap, 0, 0,
        w.toInt(), h.toInt(),
        matrix, true
    )
}

Często zadawane pytania

Czym różni się Matrix od Camera w Androidzie?

Matrix działa z dwuwymiarowymi przekształceniami afinicznymi i perspektywicznymi poprzez jedną macierz 3×3. Camera (android.graphics.Camera) — to klasa wyższego poziomu imitująca trójwymiarowy aparat: tworzy obrót 3D, a następnie projektuje wynik do 2D Matrix. Camera używa Matrix wewnętrznie.

Jak obrócić Bitmap o 90 stopni?

Utwórz Matrix z postRotate(90f) i przekaż do Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). Pamiętaj, że przy obrocie o 90 stopni szerokość i wysokość wyniku zamieniają się miejscami. Dla obrotu o dowolny kąt może być potrzebne przycięcie, aby uniknąć pustych obszarów.

Jak uzyskać odwrotne przekształcenie Matrix?

Użyj matrix.invert(resultMatrix). Metoda zwraca true, jeśli inwersja jest udana, i zapisuje odwrotną macierz w resultMatrix. Inwersja może być niemożliwa, jeśli macierz jest zdegenerowana (np. przy zerowym skalowaniu). Zawsze sprawdzaj zwracaną wartość.

Jaka jest różnica między pre i post operacjami?

pre mnoży nowe przekształcenie z lewej strony: result = operation × current — operacja jest stosowana przed bieżącymi. post mnoży z prawej strony: result = current × operation — operacja jest stosowana po. Dla sekwencji preRotate + postTranslate: najpierw obrót, potem przesunięcie.

Czy można używać Matrix w Compose?

Tak, Matrix jest używany w Jetpack Compose poprzez klasę android.graphics.Matrix w interakcji z Canvas Compose. W Compose dostępne są graphicsLayer do transformacji (scale, rotationX, translationX i inne), ale dla złożonych przekształceń Bitmap stosuje się Matrix w kodzie drawWithContent lub drawBehind.

Podsumowanie

  • Matrix — klasa Androida do przekształceń afinicznych i perspektywicznych z macierzą 3×3
  • Cztery podstawowe typy: translate (przesunięcie), scale (skalowanie), rotate (obrót), skew (pochylenie)
  • Operacje pre/post zarządzają kolejnością stosowania: pre — przed bieżącymi, post — po bieżących przekształceniach
  • setPolyToPoly — unikalna funkcja do obliczania przekształcenia perspektywicznego dla 4 par punktów
  • Matrix jest stosowana do Canvas przez concat, do Bitmap przez createBitmap z Matrix, do punktów przez mapPoints
  • invert oblicza odwrotne przekształcenie, zwracając false dla zdegenerowanych macierzy
  • isAffine i isIdentity pomagają klasyfikować stan macierzy dla optymalizacji

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również