Molte app devono essere in grado di controllare con precisione cosa viene disegnato sullo schermo. Potrebbe 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 è mediante i modificatori, ad esempio
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 come size
, un oggetto Size
che specifica le dimensioni attuali dell'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 su 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 disegnare 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 intorno a un punto pivot. 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 ti trovi in un DrawScope
o vuoi disegnare manualmente il testo con la personalizzazione, puoi utilizzare il metodo DrawScope.drawText()
.
Per disegnare il testo, crea una TextMeasurer
utilizzando rememberTextMeasurer
e chiama drawText
con lo strumento di misurazione:
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 Compose, puoi utilizzare un TextMeasurer
per avere accesso alla dimensione misurata del testo, a seconda dei 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 produce uno sfondo rosa nel testo:
La regolazione dei vincoli, delle dimensioni dei caratteri o di qualsiasi proprietà che influisce sulle dimensioni misurate genera una nuova dimensione registrata. 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 mostra il 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 è ora tracciato all'interno dei vincoli con dei puntini di sospensione 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 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ò tracciare un percorso usando 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