Matrix — là một lớp từ Android SDK (android.graphics.Matrix) biểu diễn phép biến đổi affine thông qua ma trận 3×3. Nó được sử dụng để biến đổi các đối tượng đồ họa — di chuyển, thay đổi kích thước, xoay và nghiêng. Theo Tài liệu dành cho nhà phát triển Android (2026), Matrix là công cụ chính để làm việc với các phép biến đổi trong Canvas, Bitmap và Drawable, cung cấp khả năng kiểm soát tọa độ chính xác khi vẽ tùy chỉnh.
Điểm chính
Matrix (android.graphics.Matrix) — là một lớp SDK Android biểu diễn ma trận toán học 3×3 được sử dụng để biến đổi các tọa độ hai chiều. Matrix là khối xây dựng cơ bản cho mọi biến đổi đồ họa trong Android — từ di chuyển và thay đổi kích thước Canvas đến các biến dạng phối cảnh phức tạp của Bitmap.
Không giống như iOS, sử dụng các cấu trúc riêng biệt CGAffineTransform (affine) và CATransform3D (3D), Android kết hợp các phép biến đổi affine và phối cảnh trong một lớp Matrix duy nhất. Ma trận 3×3 cho phép biểu diễn cả các thao tác affine tiêu chuẩn (hàng cuối [0, 0, 1]) và các biến dạng phối cảnh khi hàng cuối chứa các giá trị tùy ý. Điều này mang lại sự linh hoạt hơn nhưng đòi hỏi sự hiểu biết về toán học ma trận.
Matrix được tích hợp chặt chẽ với Canvas API. Khi nhà phát triển gọi canvas.translate(), canvas.scale() hoặc canvas.rotate(), các phương thức này sẽ sửa đổi ma trận của ngữ cảnh đồ họa. Bạn có thể lấy ma trận Canvas hiện tại qua canvas.getMatrix() và áp dụng thủ công ma trận tùy chỉnh qua canvas.setMatrix() hoặc canvas.concat().
Matrix hỗ trợ bốn loại biến đổi affine cơ bản: translate, scale, rotate, skew (nghiêng). Mỗi loại có các phương thức cho pre-nhân (pre), post-nhân (post) và thiết lập (set). Sự khác biệt giữa preTranslate và postTranslate nằm ở thứ tự nhân ma trận, ảnh hưởng đến biến đổi cuối cùng khi kết hợp các thao tác.
| Thao tác | Phương thức | Tham số | Mô tả |
|---|---|---|---|
| Di chuyển | setTranslate / preTranslate / postTranslate | dx, dy | Dịch chuyển dọc theo trục X và Y |
| Thay đổi kích thước | setScale / preScale / postScale | sx, sy, px, py | Thay đổi kích thước với điểm neo |
| Xoay | setRotate / preRotate / postRotate | degrees, px, py | Xoay quanh điểm neo |
| Nghiêng | setSkew / preSkew / postSkew | kx, ky | Nghiêng (cắt) dọc theo các trục |
Translate thay đổi vị trí của tất cả các điểm bằng một độ dịch chuyển dx, dy. dx dương dịch sang phải, dy — xuống dưới (trong hệ tọa độ màn hình Android, trục Y hướng xuống dưới). Translate không thay đổi hình dạng của đối tượng — chỉ vị trí của nó. Đây là thao tác đơn giản nhất và được sử dụng nhiều nhất để định vị các phần tử.
Scale thay đổi kích thước của đối tượng với các hệ số sx (dọc theo X) và sy (dọc theo Y). Các tham số px, py chỉ định điểm neo cho việc thay đổi kích thước. Nếu px, py không được chỉ định, việc thay đổi kích thước được thực hiện tương đối so với gốc tọa độ (0, 0). Khi sx = sy, đối tượng thay đổi kích thướbc đồng đều. Các giá trị âm tạo ra sự phản chiếu.
Rotate xoay một đối tượng theo một góc cho trước (tính bằng độ) quanh điểm neo (px, py). Giá trị độ dương tương ứng với xoay theo chiều kim đồng hồ (khác với iOS/macOS, nơi góc dương là ngược chiều kim đồng hồ). Nếu px, py không được thiết lập, việc xoay được thực hiện quanh gốc tọa độ.
Skew (cắt) làm biến dạng đối tượng bằng cách nghiêng nó dọc theo trục X (kx) hoặc trục Y (ky). Giá trị 1.0 nghiêng ở góc 45 độ. Skew được sử dụng để tạo hiệu ứng nghiêng, giao diện giả 3D và biến dạng phối cảnh.
Matrix lưu trữ các phần tử 3×3 của nó trong một mảng nội bộ gồm 9 giá trị dấu phẩy động (float[9]). Thứ tự lưu trữ là column-major (theo cột), phù hợp với biểu diễn toán học tiêu chuẩn. Truy cập vào các phần tử riêng lẻ được thực hiện thông qua các hằng số: Matrix.MSCALE_X, Matrix.MSKEW_Y, Matrix.MTRANS_X và các hằng khác.
Ma trận được tổ chức như sau: hai cột đầu tiên (MSCALE_X, MSKEW_X, MSKEW_Y, MSCALE_Y) xử lý việc thay đổi kích thước, xoay và nghiêng. Cột thứ ba (MTRANS_X, MTRANS_Y, MPERSP_2) xử lý việc di chuyển và phối cảnh. Đối với các phép biến đổi affine, MPERSP_0 và MPERSP_1 là 0, và MPERSP_2 là 1.
Để lấy giá trị ma trận, hãy sử dụng getValues(float[] values), phương thức này điền vào một mảng gồm 9 phần tử. Để thiết lập, hãy sử dụng setValues(float[] values). Điều này cho phép thao tác trực tiếp trên ma trận cho các biến đổi tùy chỉnh phức tạp vượt ra ngoài các phương thức translate, scale, rotate và skew tiêu chuẩn.
Matrix cung cấp một số phương thức để phân loại trạng thái hiện tại. isIdentity() kiểm tra xem ma trận có phải là ma trận đơn vị không. isAffine() kiểm tra xem nó có chỉ chứa các phép biến đổi affine hay không (MPERSP_0 = 0, MPERSP_1 = 0, MPERSP_2 = 1). Các kiểm tra này hữu ích cho việc tối ưu hóa: nếu ma trận là đơn vị, có thể bỏ qua biến đổi.
Matrix hỗ trợ một số loại thao tác: thiết lập (set), pre-nhân (pre), post-nhân (post), nối (concat), nghịch đảo (invert) và ánh xạ (map). Mỗi loại phục vụ mục đích riêng khi xây dựng các biến đổi phức tạp.
preTranslate nhân ma trận hiện tại ở bên trái với ma trận di chuyển: result = translate × current. postTranslate nhân ở bên phải: result = current × translate. Sự khác biệt nằm ở thứ tự áp dụng: các thao tác pre được áp dụng trước các biến đổi hiện tại, các thao tác post được áp dụng sau. Điều tương tự áp dụng cho preScale, postScale, preRotate, postRotate và preSkew, postSkew.
invert(Matrix inverse) tính toán ma trận nghịch đảo. Nếu ma trận gốc là suy biến (định thức bằng không), nó trả về false. concat(Matrix other) nhân ma trận hiện tại với ma trận được cung cấp: set = set × other. Để có thứ tự ngược lại, hãy sử dụng setConcat(other, this).
mapRect(RectF rect) biến đổi một hình chữ nhật và trả về kết quả trong một RectF mới. mapPoints(float[] dst, float[] src) biến đổi một mảng các điểm. mapVectors(float[] dst, float[] src) biến đổi các vectơ — mà không tính đến di chuyển. mapRect hữu ích để tính toán hộp bao sau khi biến đổi.
Matrix được sử dụng tích cực trong hai tình huống đồ họa Android chính: biến đổi Canvas và biến đổi Bitmap. Trong cả hai trường hợp, Matrix xác định cách đầu ra đồ họa sẽ được sửa đổi.
Canvas cung cấp canvas.setMatrix(matrix) để thay thế hoàn toàn ma trận hiện tại và canvas.concat(matrix) để nhân biến đổi hiện tại với ma trận được cung cấp. Sau khi áp dụng Matrix, tất cả việc vẽ tiếp theo — các lệnh gọi drawBitmap, drawRect, drawPath — được thực hiện trong hệ tọa độ đã biến đổi. Canvas cũng duy trì ngăn xếp trạng thái đã lưu của riêng mình thông qua save() và restore().
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) tạo một Bitmap mới với biến đổi được cung cấp áp dụng. Đây là một công cụ mạnh mẽ để tạo các bản sao hình ảnh được thay đổi kích thước, xoay hoặc biến dạng mà không làm mất Bitmap gốc. Tham số filter kiểm soát khử răng cưa trong quá trình nội suy pixel.
setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — một khả năng độc đáo của Matrix không có tương đương trực tiếp trong CGAffineTransform. Nó tính toán một ma trận biến đổi các điểm cho trước từ một đa giác này sang một đa giác khác. Với pointCount = 4, một phép biến đổi phối cảnh (chiếu) hoàn chỉnh được tạo ra, cho phép lớp phủ Bitmap với biến dạng phối cảnh.
Hãy xem các ví dụ thực tế về việc sử dụng Matrix để biến đổi đồ họa trong ứng dụng Android với Kotlin.
Ví dụ tạo một Matrix cho một biến đổi kết hợp: di chuyển (100, 50), thay đổi kích thước 1.5x và xoay 45 độ. Việc sử dụng postTranslate sau preRotate và preScale sẽ thay đổi thứ tự áp dụng các thao tác.
val matrix = Matrix()
matrix.preScale(1.5f, 1.5f)
matrix.preRotate(45f)
matrix.postTranslate(100f, 50f)
// Áp dụng cho các điểm
val pts = floatArrayOf(0f, 0f, 100f, 100f)
matrix.mapPoints(pts)
// Áp dụng cho hình chữ nhật
val rect = RectF(0f, 0f, 200f, 100f)
matrix.mapRect(rect)
Ví dụ minh họa việc áp dụng Matrix vào Canvas trong onDraw để xoay và thay đổi kích thước một hình tròn quanh tâm của nó. Lưu và khôi phục trạng thái Canvas đảm bảo rằng biến đổi không ảnh hưởng đến các phần tử vẽ tiếp theo.
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()
}
Ví dụ sử dụng setPolyToPoly để tạo biến dạng phối cảnh của một Bitmap. Bốn điểm nguồn (các góc của hình chữ nhật ban đầu) được ánh xạ tới bốn điểm đích tạo thành một hình thang. Kết quả là hiệu ứng hình ảnh nghiêng trong không gian.
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
)
}
Câu hỏi thường gặp
Matrix làm việc với các phép biến đổi affine và phối cảnh hai chiều thông qua một ma trận 3×3 duy nhất. Camera (android.graphics.Camera) là một lớp cấp cao hơn mô phỏng máy ảnh ba chiều: nó tạo vòng quay 3D và sau đó chiếu kết quả vào Matrix 2D. Camera sử dụng Matrix bên trong.
Tạo một Matrix với postRotate(90f) và truyền nó vào Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). Lưu ý rằng khi xoay 90 độ, chiều rộng và chiều cao của kết quả sẽ đổi chỗ cho nhau. Khi xoay một góc tùy ý, có thể cần cắt xén để tránh các vùng trống.
Sử dụng matrix.invert(resultMatrix). Phương thức trả về true nếu việc nghịch đảo thành công và ghi ma trận nghịch đảo vào resultMatrix. Việc nghịch đảo có thể không thực hiện được nếu ma trận suy biến (ví dụ, khi tỷ lệ bằng không). Luôn kiểm tra giá trị trả về.
pre nhân biến đổi mới với bên trái: result = operation × current — thao tác được áp dụng trước các biến đổi hiện tại. post nhân ở bên phải: result = current × operation — thao tác được áp dụng sau. Đối với chuỗi preRotate + postTranslate: đầu tiên xoay, sau đó di chuyển.
Có, Matrix được sử dụng trong Jetpack Compose thông qua lớp android.graphics.Matrix trong tương tác với Canvas Compose. Trong Compose, graphicsLayer có sẵn cho các biến đổi (scale, rotationX, translationX và các biến khác), nhưng đối với các biến đổi Bitmap phức tạp, Matrix được sử dụng trong mã drawWithContent hoặc drawBehind.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm