Matrix — una classe dell’SDK Android (android.graphics.Matrix) che rappresenta una trasformazione affine attraverso una matrice 3×3. Viene utilizzata per trasformare oggetti grafici — spostamento, ridimensionamento, rotazione e inclinazione. Secondo la Documentazione per Sviluppatori Android (2026), Matrix è lo strumento principale per lavorare con le trasformazioni in Canvas, Bitmap e Drawable, fornendo un controllo preciso delle coordinate nel disegno personalizzato.
Punti Chiave
Matrix (android.graphics.Matrix) — una classe dell’SDK Android che rappresenta una matrice matematica 3×3 utilizzata per trasformare coordinate bidimensionali. Matrix è il blocco fondamentale per tutte le trasformazioni grafiche in Android — dal movimento e ridimensionamento di Canvas alle complesse distorsioni prospettiche di Bitmap.
A differenza di iOS, che utilizza strutture separate CGAffineTransform (affine) e CATransform3D (3D), Android combina trasformazioni affini e prospettiche in un’unica classe Matrix. La matrice 3×3 permette di rappresentare sia le operazioni affini standard (ultima riga [0, 0, 1]) sia le distorsioni prospettiche in cui l’ultima riga contiene valori arbitrari. Ciò offre maggiore flessibilità, ma richiede la comprensione della matematica delle matrici.
Matrix è strettamente integrata con l’API Canvas. Quando uno sviluppatore chiama canvas.translate(), canvas.scale() o canvas.rotate(), questi metodi modificano internamente la matrice del contesto grafico. È possibile ottenere la matrice corrente di Canvas tramite canvas.getMatrix() e applicare manualmente una matrice personalizzata con canvas.setMatrix() o canvas.concat().
Matrix supporta quattro tipi base di trasformazioni affini: translate, scale, rotate, skew (inclinare). Ogni tipo ha metodi per pre-moltiplicazione (pre), post-moltiplicazione (post) e impostazione (set). La differenza tra preTranslate e postTranslate risiede nell’ordine di moltiplicazione delle matrici, che influisce sulla trasformazione finale quando si combinano le operazioni.
| Operazione | Metodo | Parametri | Descrizione |
|---|---|---|---|
| Spostare | setTranslate / preTranslate / postTranslate | dx, dy | Spostamento lungo gli assi X e Y |
| Ridimensionare | setScale / preScale / postScale | sx, sy, px, py | Ridimensionamento con punto pivot |
| Ruotare | setRotate / preRotate / postRotate | degrees, px, py | Rotazione intorno al punto pivot |
| Inclinare | setSkew / preSkew / postSkew | kx, ky | Inclinazione (taglio) lungo gli assi |
Translate modifica la posizione di tutti i punti di un dato spostamento dx, dy. Dx positivo sposta a destra, dy — in basso (nel sistema di coordinate dello schermo Android l’asse Y punta verso il basso). Translate non modifica la forma dell’oggetto — solo la sua posizione. È l’operazione più semplice e più utilizzata per posizionare elementi.
Scale modifica la dimensione di un oggetto con i fattori sx (lungo X) e sy (lungo Y). I parametri px, py specificano il punto pivot per il ridimensionamento. Se px, py non sono specificati, il ridimensionamento viene eseguito rispetto all’origine (0, 0). Quando sx = sy, l’oggetto si ridimensiona uniformemente. I valori negativi creano un riflesso.
Rotate ruota un oggetto di un dato angolo (in gradi) attorno a un punto pivot (px, py). I gradi positivi corrispondono alla rotazione in senso orario (a differenza di iOS/macOS, dove un angolo positivo è antiorario). Se px, py non sono impostati, la rotazione viene eseguita attorno all’origine.
Skew (taglio) deforma un oggetto inclinandolo lungo l’asse X (kx) o l’asse Y (ky). Un valore di 1.0 inclina di 45 gradi. Skew viene utilizzato per creare effetti di inclinazione, aspetti pseudo-3D e distorsione prospettica.
Matrix memorizza i suoi elementi 3×3 in un array interno di 9 valori a virgola mobile (float[9]). L’ordine di memorizzazione è column-major (per colonne), coerente con la rappresentazione matematica standard. L’accesso ai singoli elementi avviene tramite costanti: Matrix.MSCALE_X, Matrix.MSKEW_Y, Matrix.MTRANS_X e così via.
La matrice è organizzata come segue: le prime due colonne (MSCALE_X, MSKEW_X, MSKEW_Y, MSCALE_Y) gestiscono ridimensionamento, rotazione e inclinazione. La terza colonna (MTRANS_X, MTRANS_Y, MPERSP_2) gestisce traslazione e prospettiva. Per le trasformazioni affini, MPERSP_0 e MPERSP_1 sono 0, e MPERSP_2 è 1.
Per ottenere i valori della matrice, utilizzare getValues(float[] values), che riempie un array di 9 elementi. Per impostarli, utilizzare setValues(float[] values). Ciò consente la manipolazione diretta della matrice per trasformazioni personalizzate complesse oltre i metodi standard translate, scale, rotate e skew.
Matrix fornisce diversi metodi per classificare lo stato corrente. isIdentity() verifica se la matrice è identità. isAffine() verifica se contiene solo trasformazioni affini (MPERSP_0 = 0, MPERSP_1 = 0, MPERSP_2 = 1). Questi controlli sono utili per l’ottimizzazione: se la matrice è identità, la trasformazione può essere saltata.
Matrix supporta diverse categorie di operazioni: impostazione (set), pre-moltiplicazione (pre), post-moltiplicazione (post), concatenazione (concat), inversione (invert) e mappatura (map). Ogni categoria ha il suo scopo nella costruzione di trasformazioni complesse.
preTranslate moltiplica la matrice corrente a sinistra per la matrice di traslazione: result = translate × current. postTranslate moltiplica a destra: result = current × translate. La differenza sta nell’ordine di applicazione: le operazioni pre vengono applicate prima delle trasformazioni correnti, le operazioni post dopo. Lo stesso vale per preScale, postScale, preRotate, postRotate e preSkew, postSkew.
invert(Matrix inverse) calcola la matrice inversa. Se la matrice originale è singolare (determinante zero), restituisce false. concat(Matrix other) moltiplica la matrice corrente per quella fornita: set = set × other. Per l’ordine inverso, utilizzare setConcat(other, this).
mapRect(RectF rect) trasforma un rettangolo e restituisce il risultato in un nuovo RectF. mapPoints(float[] dst, float[] src) trasforma un array di punti. mapVectors(float[] dst, float[] src) trasforma vettori — senza considerare la traslazione. mapRect è utile per calcolare i bounding box dopo la trasformazione.
Matrix viene utilizzata attivamente in due scenari chiave della grafica Android: trasformazione di Canvas e trasformazione di Bitmap. In entrambi i casi, Matrix determina come verrà modificata l’uscita grafica.
Canvas fornisce canvas.setMatrix(matrix) per la sostituzione completa della matrice corrente e canvas.concat(matrix) per moltiplicare la trasformazione corrente per quella fornita. Dopo aver applicato Matrix, tutto il disegno successivo — chiamate drawBitmap, drawRect, drawPath — viene eseguito nel sistema di coordinate trasformato. Canvas mantiene anche il proprio stack di stati salvati tramite save() e restore().
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) crea un nuovo Bitmap con la trasformazione fornita applicata. Questo è un potente strumento per creare copie ridimensionate, ruotate o distorte di immagini senza perdere il Bitmap originale. Il parametro filter controlla l’anti-aliasing durante l’interpolazione dei pixel.
setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — una capacità unica di Matrix senza equivalente diretto in CGAffineTransform. Calcola una matrice che trasforma punti dati da un poligono a un altro. Con pointCount = 4, viene creata una trasformazione prospettica (proiettiva) completa, consentendo la sovrapposizione di Bitmap con distorsione prospettica.
Vediamo esempi pratici di utilizzo di Matrix per la trasformazione grafica in un’applicazione Android con Kotlin.
L’esempio crea un Matrix per una trasformazione combinata: traslazione di (100, 50), ridimensionamento di 1.5x e rotazione di 45 gradi. L’uso di postTranslate dopo preRotate e preScale modifica l’ordine di applicazione delle operazioni.
val matrix = Matrix()
matrix.preScale(1.5f, 1.5f)
matrix.preRotate(45f)
matrix.postTranslate(100f, 50f)
// Applicazione ai punti
val pts = floatArrayOf(0f, 0f, 100f, 100f)
matrix.mapPoints(pts)
// Applicazione al rettangolo
val rect = RectF(0f, 0f, 200f, 100f)
matrix.mapRect(rect)
L’esempio dimostra l’applicazione di Matrix a Canvas in onDraw per ruotare e ridimensionare un cerchio attorno al suo centro. Salvare e ripristinare lo stato di Canvas garantisce che la trasformazione non influisca sugli elementi di disegno successivi.
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()
}
L’esempio utilizza setPolyToPoly per creare una distorsione prospettica di un Bitmap. Quattro punti sorgente (angoli del rettangolo originale) vengono mappati a quattro punti destinazione che formano un trapezio. Il risultato è un effetto di immagine inclinata nello spazio.
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
)
}
Domande Frequenti
Matrix lavora con trasformazioni affini e prospettiche bidimensionali attraverso un’unica matrice 3×3. Camera (android.graphics.Camera) è una classe di livello superiore che simula una fotocamera tridimensionale: crea una rotazione 3D e poi proietta il risultato in una Matrix 2D. Camera utilizza Matrix internamente.
Creare un Matrix con postRotate(90f) e passarlo a Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). Notare che ruotando di 90 gradi, larghezza e altezza del risultato si scambiano. Per rotazioni ad angolo arbitrario, potrebbe essere necessario ritagliare per evitare aree vuote.
Utilizzare matrix.invert(resultMatrix). Il metodo restituisce true se l’inversione ha successo e scrive la matrice inversa in resultMatrix. L’inversione può essere impossibile se la matrice è singolare (ad esempio, con scala zero). Controllare sempre il valore restituito.
pre moltiplica la nuova trasformazione a sinistra: result = operation × current — l’operazione viene applicata prima di quelle correnti. post moltiplica a destra: result = current × operation — l’operazione viene applicata dopo. Per una sequenza preRotate + postTranslate: prima rotazione, poi traslazione.
Sì, Matrix viene utilizzata in Jetpack Compose attraverso la classe android.graphics.Matrix in interazione con Canvas Compose. In Compose, graphicsLayer è disponibile per le trasformazioni (scale, rotationX, translationX e altre), ma per trasformazioni complesse di Bitmap, Matrix viene utilizzata nel codice drawWithContent o drawBehind.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche