Matrix — е клас от Android SDK (android.graphics.Matrix), представляващ афинна трансформация чрез матрица 3×3. Използва се за трансформация на графични обекти — преместване, мащабиране, завъртане и накланяне. Според Android Developers Documentation (2026), Matrix е основният инструмент за работа с трансформации в Canvas, Bitmap и Drawable, осигурявайки точно управление на координатите при персонализирано рисуване.
Основни точки
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 поддържа четири основни типа афинни трансформации: translate, scale, rotate, skew (накланяне). Всеки тип има методи за пред-умножение (pre), след-умножение (post) и настройка (set). Разликата между preTranslate и postTranslate е в реда на умножение на матриците, което влияе на крайната трансформация при комбиниране.
| Операция | Метод | Параметри | Описание |
|---|---|---|---|
| Translate | setTranslate / preTranslate / postTranslate | dx, dy | Преместване по осите X и Y |
| Scale | setScale / preScale / postScale | sx, sy, px, py | Мащабиране с референтна точка |
| Rotate | setRotate / preRotate / postRotate | degrees, px, py | Завъртане около референтна точка |
| Skew | setSkew / preSkew / postSkew | kx, ky | Накланяне (плъзгане) по осите |
Translate променя позицията на всички точки с даденото преместване dx, dy. Положителното dx премества надясно, dy — надолу (в координатната система на екрана на Android оста Y е насочена надолу). Translate не променя формата на обекта — само неговата позиция. Това е най-простата и най-често използвана операция за позициониране на елементи.
Scale променя размера на обекта с коефициенти sx (по X) и sy (по Y). Параметрите px, py задават референтната точка на мащабиране (pivot point). Ако px, py не са зададени, мащабирането се извършва спрямо началото на координатите (0, 0). При sx = sy обектът се мащабира равномерно. Отрицателните стойности създават отражение.
Rotate завърта обекта на даден ъгъл (в градуси) около референтна точка (px, py). Положителната стойност на градусите съответства на завъртане по часовниковата стрелка (за разлика от iOS/macOS, където положителният ъгъл е обратно на часовниковата стрелка). Ако px, py не са зададени, завъртането се извършва около началото на координатите.
Skew (плъзгане) деформира обекта, като го накланя по оста X (kx) или оста Y (ky). Стойност 1.0 накланя на 45 градуса. Skew се използва за създаване на ефекти на наклон, симулиране на триизмерен изглед (псевдо-3D) и изкривяване на перспективата.
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 поддържа няколко категории операции: настройка (set), пред-умножение (pre), след-умножение (post), конкатенация (concat), инверсия (invert) и картографиране (map). Всяка категория решава своя задача при изграждане на сложни трансформации.
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).
mapRect(RectF rect) трансформира правоъгълника и връща резултата в нов RectF. mapPoints(float[] dst, float[] src) трансформира масив от точки. mapVectors(float[] dst, float[] src) трансформира вектори — без да отчита преместването (translate). mapRect е полезен за изчисляване на bounding box след трансформация.
Matrix се използва активно в два ключови сценария на Android графиката: трансформация на Canvas и трансформация на Bitmap. И в двата случая Matrix определя как графичният изход ще бъде променен.
Canvas предоставя методите canvas.setMatrix(matrix) за пълна замяна на текущата матрица и canvas.concat(matrix) за умножение на текущата трансформация по подадената. След прилагане на Matrix, цялото последващо рисуване — извиквания на drawBitmap, drawRect, drawPath — се извършва в трансформираната координатна система. Canvas също поддържа свой собствен стек от запазени състояния чрез save() и restore().
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) създава нов Bitmap с прилагане на зададената трансформация. Това е мощен инструмент за създаване на мащабирани, завъртяни или деформирани копия на изображения без загуба на оригиналния Bitmap. Параметърът filter контролира изглаждането при интерполация на пиксели.
setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — уникална възможност на Matrix, без пряк аналог в CGAffineTransform. Тя изчислява матрица, която трансформира дадени точки от един многоъгълник в друг. При pointCount = 4 се създава пълна перспективна (projective) трансформация, позволяваща нанасяне на Bitmap с изкривяване на перспективата.
Нека разгледаме практически примери за използване на Matrix за графична трансформация в Android приложение на Kotlin.
Примерът създава Matrix за комбинирана трансформация: преместване с (100, 50), мащабиране 1.5 пъти и завъртане на 45 градуса. Използването на postTranslate след preRotate и preScale променя реда на прилагане на операциите.
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)
Примерът демонстрира прилагане на Matrix към Canvas в onDraw за завъртане и мащабиране на кръг около неговия център. Запазването и възстановяването на състоянието на Canvas гарантира, че трансформацията няма да повлияе на последващите елементи за рисуване.
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 за създаване на перспективно изкривяване на Bitmap. Четири изходни точки (ъгли на оригиналния правоъгълник) се картографират към четири целеви точки, образуващи трапец. Резултатът — ефект на изображение, наклонено в пространството.
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 работи с двумерни афинни и перспективни трансформации чрез една матрица 3×3. Camera (android.graphics.Camera) — е клас от по-високо ниво, който симулира триизмерна камера: създава 3D завъртане и след това проектира резултата в 2D Matrix. Camera използва Matrix вътрешно.
Създайте Matrix с postRotate(90f) и го предайте на Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). Имайте предвид, че при завъртане на 90 градуса ширината и височината на резултата се разменят. За завъртане на произволен ъгъл може да се наложи изрязване, за да се избегнат празни области.
Използвайте matrix.invert(resultMatrix). Методът връща true, ако инверсията е успешна, и записва обратната матрица в resultMatrix. Инверсията може да бъде невъзможна, ако матрицата е дегенерирана (например при нулев мащаб). Винаги проверявайте върнатата стойност.
pre умножава новата трансформация отляво: result = operation × current — операцията се прилага преди текущите трансформации. post умножава отдясно: result = current × operation — операцията се прилага след текущите трансформации. За последователността preRotate + postTranslate: първо завъртане, после преместване.
Да, Matrix се използва в Jetpack Compose чрез класа android.graphics.Matrix във взаимодействие с Canvas Compose. В Compose, graphicsLayer е наличен за трансформация (scale, rotationX, translationX и други), но за сложни трансформации на Bitmap, Matrix се прилага в кода drawWithContent или drawBehind.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също