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.getMatrix()获取Canvas的当前矩阵,并通过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不同,在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用于计算变换后的边界框。
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。
让我们看看在Kotlin的Android应用中使用Matrix进行图形变换的实际示例。
示例创建一个用于组合变换的Matrix:平移(100, 50)、缩放1.5倍和旋转45度。在preRotate和preScale之后使用postTranslate会改变操作的应用顺序。
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)
示例演示了在onDraw中将Matrix应用于Canvas以围绕其中心旋转和缩放圆形。保存和恢复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。
创建一个带有postRotate(90f)的Matrix并将其传递给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自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。