Molte app devono essere in grado di controllare con precisione cosa viene disegnato sullo schermo. Potrebbe trattarsi di un semplice riquadro o cerchio sullo schermo posizionato nel punto giusto oppure di una complessa disposizione di elementi grafici in molti stili diversi.
Disegno di base con modificatori e DrawScope
Il modo principale per disegnare qualcosa di personalizzato in Compose è con i modificatori, come
Modifier.drawWithContent
,
Modifier.drawBehind
e
Modifier.drawWithCache
.
Ad esempio, per disegnare qualcosa dietro il composable, puoi utilizzare il
modificatore drawBehind
per iniziare a eseguire i comandi di disegno:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Se ti serve solo un composable che disegni, puoi utilizzare il composable
Canvas
. Il componente componibile Canvas
è un
wrapper pratico per Modifier.drawBehind
. Posiziona Canvas
nel layout come faresti con qualsiasi altro elemento dell'interfaccia utente Compose. All'interno di
Canvas
, puoi disegnare elementi con un controllo preciso su stile e
posizione.
Tutti i modificatori di disegno espongono un DrawScope
, un ambiente di disegno con ambito
che mantiene il proprio stato. In questo modo puoi impostare i parametri per un gruppo di
elementi grafici. DrawScope
fornisce diversi campi utili, come size
,
un oggetto Size
che specifica le dimensioni attuali di DrawScope
.
Per disegnare qualcosa, puoi utilizzare una delle tante funzioni di disegno su DrawScope
. Ad esempio, il seguente codice disegna un rettangolo nell'angolo in alto a sinistra dello schermo:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }

Per scoprire di più sui diversi modificatori di disegno, consulta la documentazione relativa ai modificatori grafici.
Sistema di coordinate
Per disegnare qualcosa sullo schermo, devi conoscere l'offset (x
e y
) e le dimensioni
dell'elemento. Con molti dei metodi di disegno su DrawScope
, la posizione e le dimensioni
sono fornite dai valori predefiniti dei parametri. I parametri predefiniti in genere
posizionano l'elemento nel punto [0, 0]
del canvas e forniscono un size
predefinito
che riempie l'intera area di disegno, come nell'esempio precedente. Puoi notare
che il rettangolo è posizionato in alto a sinistra. Per regolare le dimensioni e la posizione
dell'elemento, devi comprendere il sistema di coordinate in Compose.
L'origine del sistema di coordinate ([0,0]
) si trova nel pixel più in alto a sinistra dell'area di disegno. x
aumenta man mano che si sposta verso destra e y
aumenta man mano che si sposta
verso il basso.
![Una griglia che mostra il sistema di coordinate con l'angolo in alto a sinistra [0, 0] e l'angolo in basso a destra [larghezza, altezza]](https://developer.android.com/static/develop/ui/compose/images/graphics/introduction/compose_coordinate_system_drawing.png?authuser=19&hl=it)
Ad esempio, se vuoi tracciare una linea diagonale dall'angolo in alto a destra
dell'area del canvas all'angolo in basso a sinistra, puoi utilizzare la
funzione DrawScope.drawLine()
e specificare un offset iniziale e finale con
le posizioni x e y corrispondenti:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
Trasformazioni di base
DrawScope
offre trasformazioni per modificare dove o come vengono eseguiti i comandi di disegno.
Diffusione
Utilizza
DrawScope.scale()
per aumentare le dimensioni delle operazioni di disegno di un fattore. Operazioni come
scale()
si applicano a tutte le operazioni di disegno all'interno della lambda corrispondente. Ad esempio, il seguente codice aumenta scaleX
di 10 volte e scaleY
di 15 volte:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }

Traduci
Utilizza
DrawScope.translate()
per spostare le operazioni di disegno verso l'alto, il basso, sinistra o destra. Ad esempio, il
seguente codice sposta il disegno di 100 px a destra e di 300 px in alto:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }

Ruota
Usa
DrawScope.rotate()
per ruotare le operazioni di disegno intorno a un punto di rotazione. Ad esempio, il
seguente codice ruota un rettangolo di 45 gradi:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

rotate()
per applicare una rotazione all'ambito di disegno corrente, che ruota il rettangolo di 45 gradi.
Inset
Utilizza DrawScope.inset()
per regolare i parametri predefiniti dell'attuale
DrawScope
, modificando i limiti di disegno e traslando i disegni
di conseguenza:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Questo codice aggiunge in modo efficace il padding ai comandi di disegno:

Più trasformazioni
Per applicare più trasformazioni ai disegni, utilizza la funzione
DrawScope.withTransform()
, che crea e
applica una singola trasformazione che combina tutte le modifiche che vuoi apportare. L'utilizzo di
withTransform()
è più efficiente rispetto all'esecuzione di chiamate nidificate a singole
trasformazioni, perché tutte le trasformazioni vengono eseguite insieme in una
singola operazione, anziché Compose che deve calcolare e salvare ciascuna delle
trasformazioni nidificate.
Ad esempio, il seguente codice applica sia una traslazione che una rotazione al rettangolo:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

withTransform
per applicare sia una rotazione che una traslazione, ruotando il rettangolo e spostandolo a sinistra.Operazioni di disegno comuni
Disegna testo
Per disegnare il testo in Compose, in genere puoi utilizzare il composable Text
. Tuttavia,
se ti trovi in un DrawScope
o vuoi disegnare il testo manualmente con
la personalizzazione, puoi utilizzare il metodo
DrawScope.drawText()
.
Per disegnare il testo, crea un TextMeasurer
utilizzando rememberTextMeasurer
e chiama drawText
con lo strumento di misurazione:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }

Misura del testo
Il testo del disegno funziona in modo leggermente diverso rispetto ad altri comandi di disegno. Normalmente, dai al comando di disegno le dimensioni (larghezza e altezza) con cui disegnare la forma/l'immagine. Con il testo, esistono alcuni parametri che controllano le dimensioni del testo di rendering, come dimensioni del carattere, carattere, legature e spaziatura tra le lettere.
Con Compose, puoi utilizzare un TextMeasurer
per accedere alle dimensioni misurate del testo, a seconda dei fattori sopra indicati. Se vuoi disegnare uno sfondo
dietro il testo, puoi utilizzare le informazioni misurate per ottenere le dimensioni
dell'area occupata dal testo:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Questo snippet di codice produce uno sfondo rosa sul testo:

La modifica dei vincoli, delle dimensioni del carattere o di qualsiasi proprietà che influisce sulle dimensioni misurate
comporta la segnalazione di una nuova dimensione. Puoi impostare una dimensione fissa sia per width
che per height
e il testo segue poi la TextOverflow
impostata. Ad
esempio, il seguente codice esegue il rendering del testo in ⅓ dell'altezza e ⅓ della larghezza
dell'area componibile e imposta TextOverflow
su TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Il testo viene ora disegnato nei vincoli con un'ellissi alla fine:

TextOverflow.Ellipsis
con vincoli fissi sulla misurazione del testo.Disegna immagine
Per disegnare un ImageBitmap
con DrawScope
, carica l'immagine utilizzando
ImageBitmap.imageResource()
e poi chiama drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })

ImageBitmap
su Canvas.Disegnare forme di base
DrawScope
offre molte funzioni di disegno di forme. Per disegnare una forma, utilizza una delle funzioni di disegno predefinite, ad esempio drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Output |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
Percorso di disegno
Un percorso è una serie di istruzioni matematiche che, una volta eseguite, danno vita a un disegno. DrawScope
può disegnare un percorso utilizzando il metodo DrawScope.drawPath()
.
Ad esempio, supponiamo che tu voglia disegnare un triangolo. Puoi generare un percorso con
funzioni come lineTo()
e moveTo()
utilizzando le dimensioni dell'area di disegno.
Poi chiama drawPath()
con questo percorso appena creato per ottenere un triangolo.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )

Path
in Compose.Accesso all'oggetto Canvas
Con DrawScope
, non hai accesso diretto a un oggetto Canvas
. Puoi utilizzare
DrawScope.drawIntoCanvas()
per accedere
all'oggetto Canvas
stesso su cui puoi chiamare le funzioni.
Ad esempio, se hai un Drawable
personalizzato che vuoi disegnare sulla tela, puoi accedere alla tela e chiamare Drawable#draw()
, passando l'oggetto Canvas
:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )

Drawable
.Scopri di più
Per ulteriori informazioni su Disegno in Compose, consulta le seguenti risorse:
- Modificatori grafici: scopri i diversi tipi di modificatori di disegno.
- Pennello: scopri come personalizzare la pittura dei tuoi contenuti.
- Layout e grafiche personalizzati in Compose - Android Dev Summit 2022 - Scopri come creare una UI personalizzata in Compose con layout e grafiche.
- Esempio JetLagged: crea un esempio che mostri come disegnare un grafico personalizzato.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori di grafica
- Grafica in Composizione
- Linee di allineamento in Jetpack Compose