Molte app devono essere in grado di controllare con precisione cosa viene disegnato sullo schermo. Può trattarsi di un'azione semplice come inserire una casella o un cerchio sullo schermo nel punto giusto o di un'elaborata 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 disegna, puoi utilizzare il composable Canvas
. Il composable Canvas
è un wrapper comodo per Modifier.drawBehind
. Posiziona Canvas
nel
layout come faresti con qualsiasi altro elemento dell'interfaccia utente di Compose. All'interno di Canvas
, puoi disegnare elementi con un controllo preciso sul loro stile e sulla loro 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, ad esempio size
,
un oggetto Size
che specifica le dimensioni attuali del DrawScope
.
Per disegnare qualcosa, puoi utilizzare una delle numerose funzioni di disegno in 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 draw in DrawScope
, la posizione e le dimensioni vengono fornite dai valori predefiniti dei parametri. In genere, i parametri predefiniti posizionano l'elemento nel punto [0, 0]
della tela e forniscono un valore size
predefinito che riempie l'intera area di disegno, come nell'esempio precedente. Puoi vedere 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 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.
Ad esempio, se vuoi tracciare una linea diagonale dall'angolo in alto a destra dell'area della tela 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 funzione lambda corrispondente. Ad esempio, il seguente codice aumenta scaleX
10 volte e scaleY
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, verso il basso, a sinistra o a destra. Ad esempio, il
seguente codice sposta il disegno di 100 px a destra e di 300 px verso l'alto:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
Ruota
Utilizza
DrawScope.rotate()
per ruotare le operazioni di disegno attorno 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 ) } }
Inset
Utilizza DrawScope.inset()
per modificare i parametri predefiniti dell'DrawScope
corrente, cambiando i confini dei disegni e traducendoli di conseguenza:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Questo codice aggiunge efficacemente spaziatura 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 desiderate. L'utilizzo di
withTransform()
è più efficiente rispetto all'esecuzione di chiamate nidificate alle singole
trasformazioni, perché tutte le trasformazioni vengono eseguite insieme in un
unica operazione, anziché dover calcolare e salvare ciascuna delle
trasformazioni nidificate.
Ad esempio, il seguente codice applica sia una traslazione che una rotazione al quadrato:
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 ) } }
Operazioni di disegno comuni
Disegna testo
Per disegnare il testo in Componi, in genere puoi utilizzare il composable Text
. Tuttavia, se sei in un DrawScope
o vuoi disegnare il testo manualmente con personalizzazione, puoi utilizzare il metodo DrawScope.drawText()
.
Per disegnare il testo, crea un TextMeasurer
utilizzando rememberTextMeasurer
e chiama drawText
con il misuratore:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Misura il testo
Il testo disegnato funziona in modo leggermente diverso rispetto agli altri comandi di disegno. In genere, al comando di disegno vengono assegnate le dimensioni (larghezza e altezza) in cui disegnare la forma/l'immagine. Per il testo, esistono alcuni parametri che controllano le dimensioni del testo visualizzato, ad esempio le dimensioni del carattere, il carattere, le legature e la spaziatura tra le lettere.
Con Scrivi, puoi utilizzare un TextMeasurer
per accedere alle dimensioni misurate del testo, in base ai fattori sopra indicati. Se vuoi disegnare un 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 genera uno sfondo rosa per il testo:
La modifica dei vincoli, delle dimensioni dei caratteri o di qualsiasi proprietà che influisce sulle dimensioni misurate comporta la generazione di una nuova dimensione. Puoi impostare una dimensione fissa sia per width
che per height
, in modo che il testo segua l'impostazione TextOverflow
. 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:
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) })
Disegnare forme di base
DrawScope
offre molte funzioni per il 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 |
Disegna percorso
Un percorso è una serie di istruzioni matematiche che generano un disegno una volta eseguite. 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.
Quindi, 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() )
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 canvas, puoi accedere alla canvas 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() )
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 grafica personalizzati in Compose - Android Dev Summit 2022 - Scopri come creare un'interfaccia utente personalizzata in Compose con layout e grafica.
- Esempio JetLagged: esempio di composizione che mostra come disegnare un grafico personalizzato.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori di grafica
- Grafica in Compose
- Linee di allineamento in Jetpack Compose