Matrix — Android SDK(android.graphics.Matrix)의 클래스로, 3×3 행렬을 통해 애피니 변환을 나타냅니다. 그래픽 객체를 변환하는 데 사용됩니다 — 이동, 크기 변경, 회전 및 기울기. Android Developers Documentation(2026)에 따르면, Matrix는 Canvas, Bitmap 및 Drawable에서 변환을 위한 주요 도구로, 커스텀 그리기에서 정확한 좌표 제어를 제공합니다.
주요 포인트
Matrix(android.graphics.Matrix) — 2차원 좌표를 변환하기 위한 수학적 3×3 행렬을 나타내는 Android SDK의 클래스입니다. Matrix는 Canvas의 이동 및 크기 변경부터 Bitmap의 복잡한 원근 변형까지, Android에서 모든 그래픽 변환의 기본 빌딩 블록입니다.
별도의 CGAffineTransform(애피니) 및 CATransform3D(3D) 구조를 사용하는 iOS와 달리, 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의 차이는 행렬 곱셈의 순서에 있으며, 작업을 결합할 때 최종 변환에 영향을 미칩니다.
| 작업 | 메소드 | 매개변수 | 설명 |
|---|---|---|---|
| 이동 | setTranslate / preTranslate / postTranslate | dx, dy | X 및 Y 축에 따른 이동 |
| 크기 변경 | setScale / preScale / postScale | sx, sy, px, py | 피봇 포인트를 중심으로 크기 변경 |
| 회전 | setRotate / preRotate / postRotate | degrees, px, py | 피봇 포인트를 중심으로 회전 |
| 기울기 | setSkew / preSkew / postSkew | kx, ky | 축에 따른 기울기(전단) |
Translate는 지정된 이동량 dx, dy만큼 모든 점의 위치를 변경합니다. 양수 dx는 오른쪽으로, dy는 아래쪽으로(안드로이드 화면 좌표계에서 Y축은 아래를 가리킵니다) 이동시킵니다. Translate는 객체의 형태를 변경하지 않습니다 — 위치만 변경합니다. 이는 요소를 배치하는 가장 간단하고 가장 자주 사용되는 작업입니다.
Scale은 계수 sx(X 방향)와 sy(Y 방향)로 객체의 크기를 변경합니다. 매개변수 px, py는 크기 변경의 피봇 포인트를 지정합니다. 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)는 역행렬을 계산합니다. 원래 행렬이 비정규(행렬식이 0)인 경우 false를 반환합니다. concat(Matrix other)는 현재 행렬에 주어진 행렬을 곱합니다: set = set × other. 역 순서에는 setConcat(other, this)를 사용합니다.
mapRect(RectF rect)은 직사각형을 변환하고 결과를 새로운 RectF에 반환합니다. mapPoints(float[] dst, float[] src)는 점의 배열을 변환합니다. mapVectors(float[] dst, float[] src)는 이동을 고려하지 않고 벡터를 변환합니다. 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) — CGAffineTransform에 직접적인 대응물이 없는 Matrix의 고유한 기능입니다. 즐은 다각형에서 다른 다각형으로 점을 변환하는 행렬을 계산합니다. pointCount = 4일 때, 완전한 원근(투영) 변환이 만들어지고, 원근 변형을 가진 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에서 Canvas에 Matrix 적용을 보여줍니다. 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 행렬을 통해 2차원 애피니 및 원근 변환을 처리합니다. Camera(android.graphics.Camera)는 3차원 카메라를 시뮬레이팅하는 더 높은 레벨의 클래스입니다: 3D 회전을 만들고 결과를 2D Matrix로 투영합니다. Camera는 내부적으로 Matrix를 사용합니다.
postRotate(90f)로 Matrix를 만들고 Bitmap.createBitmap(original, 0, 0, w, h, matrix, true)에 전달하세요. 90도 회전할 때 결과의 너비와 높이가 서로 바껉니다. 임의의 각도로 회전할 때는 빈 영역을 피하기 위해 자르기가 필요할 수 있습니다.
matrix.invert(resultMatrix)를 사용하세요. 역행렬이 성공적으로 계산되면 true를 반환하고 역 행렬을 resultMatrix에 기록합니다. 행렬이 비정규인 경우(예: 크기 변경이 0인 경우) 역행렬이 불가능할 수 있습니다. 환수값을 확인하세요.
pre는 새 변환을 왼쪽에서 곱합니다: result = operation × current — 작업이 현재 것 전에 적용됩니다. post는 오른쪽에서 곱합니다: result = current × operation — 작업이 그 후에 적용됩니다. preRotate + postTranslate 순서의 경우: 먼저 회전, 그 다음 이동입니다.
네, Matrix는 Jetpack Compose에서 Canvas Compose와의 상호작용에서 android.graphics.Matrix 클래스를 통해 사용됩니다. Compose에서는 변환(scale, rotationX, translationX 등)을 위해 graphicsLayer가 제공되지만, 복잡한 Bitmap 변환에는 drawWithContent 또는 drawBehind 코드에서 Matrix가 사용됩니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.