Matrix в Android: какво е, видове матрици и работа с трансформации

Автор: IT Sectr Публикувано: 2026-07-22 Време за четене: 9 мин

Matrix — е клас от Android SDK (android.graphics.Matrix), представляващ афинна трансформация чрез матрица 3×3. Използва се за трансформация на графични обекти — преместване, мащабиране, завъртане и накланяне. Според Android Developers Documentation (2026), Matrix е основният инструмент за работа с трансформации в Canvas, Bitmap и Drawable, осигурявайки точно управление на координатите при персонализирано рисуване.

Основни точки

  • Matrix — Android клас за афинни и перспективни трансформации с матрица 3×3
  • Афинни операции: translate (преместване), scale (мащаб), rotate (завъртане) и skew (накланяне)
  • Matrix поддържа перспективни (projective) трансформации чрез setPolyToPoly
  • Редът на прилагане на операциите е важен — Matrix.concat извършва последователно умножение
  • Matrix се прилага към Canvas, Bitmap, RectF, PointF и Path в Android графиката

Какво е Matrix в Android?

Matrix (android.graphics.Matrix) — е клас от Android SDK, представляващ математическа матрица 3×3, използвана за трансформиране на двумерни координати. Matrix е основният градивен елемент за всички графични трансформации в Android — от преместване и мащабиране на Canvas до сложни перспективни изкривявания на Bitmap.

За разлика от iOS, където се използват отделни структури CGAffineTransform (афинни) и CATransform3D (3D), Android обединява афинните и перспективните трансформации в един клас Matrix. Матрицата 3×3 позволява представяне както на стандартни афинни операции (последен ред [0, 0, 1]), така и на перспективни изкривявания, когато последният ред съдържа произволни стойности. Това дава повече гъвкавост, но изисква разбиране на математиката на матриците.

Matrix е тясно интегриран с Canvas API. Когато разработчикът извика canvas.translate(), canvas.scale() или canvas.rotate(), тези методи вътрешно модифицират матрицата на графичния контекст. Текущата матрица на Canvas може да бъде получена чрез canvas.getMatrix(), а персонализирана матрица може да бъде приложена ръчно чрез canvas.setMatrix() или canvas.concat().

Видове трансформации на Matrix

Matrix поддържа четири основни типа афинни трансформации: translate, scale, rotate, skew (накланяне). Всеки тип има методи за пред-умножение (pre), след-умножение (post) и настройка (set). Разликата между preTranslate и postTranslate е в реда на умножение на матриците, което влияе на крайната трансформация при комбиниране.

ОперацияМетодПараметриОписание
TranslatesetTranslate / preTranslate / postTranslatedx, dyПреместване по осите X и Y
ScalesetScale / preScale / postScalesx, sy, px, pyМащабиране с референтна точка
RotatesetRotate / preRotate / postRotatedegrees, px, pyЗавъртане около референтна точка
SkewsetSkew / preSkew / postSkewkx, kyНакланяне (плъзгане) по осите

Translate — преместване

Translate променя позицията на всички точки с даденото преместване dx, dy. Положителното dx премества надясно, dy — надолу (в координатната система на екрана на Android оста Y е насочена надолу). Translate не променя формата на обекта — само неговата позиция. Това е най-простата и най-често използвана операция за позициониране на елементи.

Scale — мащаб

Scale променя размера на обекта с коефициенти sx (по X) и sy (по Y). Параметрите px, py задават референтната точка на мащабиране (pivot point). Ако px, py не са зададени, мащабирането се извършва спрямо началото на координатите (0, 0). При sx = sy обектът се мащабира равномерно. Отрицателните стойности създават отражение.

Rotate — завъртане

Rotate завърта обекта на даден ъгъл (в градуси) около референтна точка (px, py). Положителната стойност на градусите съответства на завъртане по часовниковата стрелка (за разлика от iOS/macOS, където положителният ъгъл е обратно на часовниковата стрелка). Ако px, py не са зададени, завъртането се извършва около началото на координатите.

Skew — накланяне

Skew (плъзгане) деформира обекта, като го накланя по оста X (kx) или оста Y (ky). Стойност 1.0 накланя на 45 градуса. Skew се използва за създаване на ефекти на наклон, симулиране на триизмерен изглед (псевдо-3D) и изкривяване на перспективата.

Структура на матрицата 3×3

Matrix съхранява елементите на матрицата 3×3 във вътрешен масив от 9 стойности с плаваща запетая (float[9]). Редът на съхранение е column-major (по колони), което съответства на стандартното математическо представяне. Достъпът до отделни елементи се осъществява чрез константи: Matrix.MSCALE_X, Matrix.MSKEW_Y, Matrix.MTRANS_X и така нататък.

Елементи на матрицата

Матрицата е организирана по следния начин: първите две колони (MSCALE_X, MSKEW_X, MSKEW_Y, MSCALE_Y) отговарят за мащабиране, завъртане и накланяне. Третата колона (MTRANS_X, MTRANS_Y, MPERSP_2) — за преместване и перспектива. За афинна трансформация MPERSP_0 и MPERSP_1 са равни на 0, а MPERSP_2 е равен на 1.

За получаване на стойностите на матрицата се използва getValues(float[] values), което попълва масив от 9 елемента. За настройка — setValues(float[] values). Това позволява директно манипулиране на матрицата за сложни персонализирани трансформации, надхвърлящи стандартните методи translate, scale, rotate и skew.

Проверка на типа матрица

Matrix предоставя няколко метода за класифициране на текущото състояние. isIdentity() проверява дали матрицата е единична. isAffine() — дали съдържа само афинни трансформации (MPERSP_0 = 0, MPERSP_1 = 0, MPERSP_2 = 1). Тези проверки са полезни за оптимизация: ако матрицата е единична, трансформацията може да бъде пропусната.

Основни операции с Matrix

Matrix поддържа няколко категории операции: настройка (set), пред-умножение (pre), след-умножение (post), конкатенация (concat), инверсия (invert) и картографиране (map). Всяка категория решава своя задача при изграждане на сложни трансформации.

Pre и Post операции

preTranslate умножава текущата матрица отляво по матрицата на преместване: result = translate × current. postTranslate умножава отдясно: result = current × translate. Разликата е в реда на прилагане: pre-операциите се прилагат преди текущите трансформации, post-операциите — след. Аналогично работят preScale, postScale, preRotate, postRotate и preSkew, postSkew.

Инверсия и конкатенация

invert(Matrix inverse) изчислява обратната матрица. Ако изходната матрица е дегенерирана (детерминантата е нула), се връща false. concat(Matrix other) умножава текущата матрица по подадената: set = set × other. За обратен ред използвайте setConcat(other, this).

Map — прилагане към точки и правоъгълници

mapRect(RectF rect) трансформира правоъгълника и връща резултата в нов RectF. mapPoints(float[] dst, float[] src) трансформира масив от точки. mapVectors(float[] dst, float[] src) трансформира вектори — без да отчита преместването (translate). mapRect е полезен за изчисляване на bounding box след трансформация.

Приложение в Canvas и Bitmap

Matrix се използва активно в два ключови сценария на Android графиката: трансформация на Canvas и трансформация на Bitmap. И в двата случая Matrix определя как графичният изход ще бъде променен.

Canvas трансформация чрез Matrix

Canvas предоставя методите canvas.setMatrix(matrix) за пълна замяна на текущата матрица и canvas.concat(matrix) за умножение на текущата трансформация по подадената. След прилагане на Matrix, цялото последващо рисуване — извиквания на drawBitmap, drawRect, drawPath — се извършва в трансформираната координатна система. Canvas също поддържа свой собствен стек от запазени състояния чрез save() и restore().

Bitmap трансформация чрез Matrix

Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) създава нов Bitmap с прилагане на зададената трансформация. Това е мощен инструмент за създаване на мащабирани, завъртяни или деформирани копия на изображения без загуба на оригиналния Bitmap. Параметърът filter контролира изглаждането при интерполация на пиксели.

setPolyToPoly — перспективни трансформации

setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — уникална възможност на Matrix, без пряк аналог в CGAffineTransform. Тя изчислява матрица, която трансформира дадени точки от един многоъгълник в друг. При pointCount = 4 се създава пълна перспективна (projective) трансформация, позволяваща нанасяне на Bitmap с изкривяване на перспективата.

Примери за код в Kotlin

Нека разгледаме практически примери за използване на Matrix за графична трансформация в Android приложение на Kotlin.

Основни афинни трансформации

Примерът създава Matrix за комбинирана трансформация: преместване с (100, 50), мащабиране 1.5 пъти и завъртане на 45 градуса. Използването на postTranslate след preRotate и preScale променя реда на прилагане на операциите.

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

// Прилагане към точки
val pts = floatArrayOf(0f, 0f, 100f, 100f)
matrix.mapPoints(pts)

// Прилагане към правоъгълник
val rect = RectF(0f, 0f, 200f, 100f)
matrix.mapRect(rect)

Canvas трансформация с save и restore

Примерът демонстрира прилагане на Matrix към Canvas в onDraw за завъртане и мащабиране на кръг около неговия център. Запазването и възстановяването на състоянието на Canvas гарантира, че трансформацията няма да повлияе на последващите елементи за рисуване.

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()
}

Перспективно изкривяване чрез setPolyToPoly

Примерът използва setPolyToPoly за създаване на перспективно изкривяване на Bitmap. Четири изходни точки (ъгли на оригиналния правоъгълник) се картографират към четири целеви точки, образуващи трапец. Резултатът — ефект на изображение, наклонено в пространството.

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
    )
}

Често задавани въпроси

Как се различава Matrix от Camera в Android?

Matrix работи с двумерни афинни и перспективни трансформации чрез една матрица 3×3. Camera (android.graphics.Camera) — е клас от по-високо ниво, който симулира триизмерна камера: създава 3D завъртане и след това проектира резултата в 2D Matrix. Camera използва Matrix вътрешно.

Как да завъртя Bitmap на 90 градуса?

Създайте Matrix с postRotate(90f) и го предайте на Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). Имайте предвид, че при завъртане на 90 градуса ширината и височината на резултата се разменят. За завъртане на произволен ъгъл може да се наложи изрязване, за да се избегнат празни области.

Как да получа обратната трансформация на Matrix?

Използвайте matrix.invert(resultMatrix). Методът връща true, ако инверсията е успешна, и записва обратната матрица в resultMatrix. Инверсията може да бъде невъзможна, ако матрицата е дегенерирана (например при нулев мащаб). Винаги проверявайте върнатата стойност.

Каква е разликата между pre и post операциите?

pre умножава новата трансформация отляво: result = operation × current — операцията се прилага преди текущите трансформации. post умножава отдясно: result = current × operation — операцията се прилага след текущите трансформации. За последователността preRotate + postTranslate: първо завъртане, после преместване.

Може ли да се използва Matrix в Compose?

Да, Matrix се използва в Jetpack Compose чрез класа android.graphics.Matrix във взаимодействие с Canvas Compose. В Compose, graphicsLayer е наличен за трансформация (scale, rotationX, translationX и други), но за сложни трансформации на Bitmap, Matrix се прилага в кода drawWithContent или drawBehind.

Обобщение

  • Matrix — Android клас за афинни и перспективни трансформации с матрица 3×3
  • Четири основни типа: translate (преместване), scale (мащаб), rotate (завъртане), skew (накланяне)
  • pre/post операции управляват реда на прилагане: pre — преди текущите трансформации, post — след текущите трансформации
  • setPolyToPoly — уникална функция за изчисляване на перспективна трансформация за 4 двойки точки
  • Matrix се прилага към Canvas чрез concat, към Bitmap чрез createBitmap с Matrix, към точки чрез mapPoints
  • invert изчислява обратната трансформация, връщайки false за дегенерирани матрици
  • isAffine и isIdentity помагат за класифициране на състоянието на матрицата за оптимизация

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също