Molte app devono poter controllare con precisione ciò che viene disegnato sullo schermo. Potrebbe trattarsi di un piccolo spazio, come posizionare un riquadro o un cerchio sullo schermo nel posto giusto, o una disposizione elaborata di elementi grafici in molti stili diversi.
Disegno di base con modificatori e DrawScope
Il modo principale per disegnare qualcosa di personalizzato in Compose è tramite modificatori come
Modifier.drawWithContent
,
Modifier.drawBehind
e
Modifier.drawWithCache
.
Ad esempio, per disegnare qualcosa dietro il componibile, puoi usare il modificatore drawBehind
per iniziare a eseguire comandi di disegno:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Se ti serve solo un componibile che disegna, puoi utilizzare il componibile Canvas
. Il componibile Canvas
è un
utile involucro intorno a Modifier.drawBehind
. Posiziona Canvas
nel layout come faresti con qualsiasi altro elemento dell'interfaccia utente di Compose. All'interno dell'Canvas
, puoi disegnare elementi con un controllo preciso su stile e posizione.
Tutti i modificatori di disegno espongono DrawScope
, un ambiente di disegno con ambito che mantiene il proprio stato. Ciò consente di impostare i parametri per un
gruppo di elementi grafici. DrawScope
fornisce diversi campi utili, come size
,
un oggetto Size
che specifica le dimensioni correnti di DrawScope
.
Per disegnare qualcosa, puoi usare una delle numerose funzioni di disegno disponibili 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 metodi di disegno su DrawScope
, la posizione e le dimensioni
sono fornite dai valori predefiniti dei parametri. I parametri predefiniti generalmente
posizionano l'elemento nel punto [0, 0]
del canvas e forniscono un valore
size
predefinito che riempie l'intera area di disegno, come nell'esempio sopra. Come puoi vedere
il rettangolo è posizionato in alto a sinistra. Per regolare le dimensioni e la posizione
dell'elemento, devi comprendere il sistema di coordinate di Compose.
L'origine del sistema di coordinate ([0,0]
) si trova nel pixel più in alto a sinistra nell'area di disegno. x
aumenta mentre si muove a 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 del canvas all'angolo in basso a sinistra, puoi utilizzare la funzione DrawScope.drawLine()
e specificare un offset di inizio e fine 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 cambiare dove o come vengono eseguiti i comandi di disegno.
Scala
Utilizza DrawScope.scale()
per aumentare di un fattore le dimensioni delle operazioni di disegno. Operazioni come
scale()
si applicano a tutte le operazioni di disegno all'interno della funzione 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 in alto, in 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 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 ) } }
Interno
Utilizza DrawScope.inset()
per regolare i parametri predefiniti dell'attuale
DrawScope
, modificando i limiti del disegno e traducendo 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 efficacemente spaziatura interna ai comandi di disegno:
Trasformazioni multiple
Per applicare più trasformazioni ai disegni, utilizza la funzione DrawScope.withTransform()
, che crea e applica un'unica trasformazione che combina tutte le modifiche desiderate. L'utilizzo di
withTransform()
è più efficiente dell'esecuzione di chiamate nidificate a singole trasformazioni, perché tutte le trasformazioni vengono eseguite insieme in una
singola operazione, invece di dover calcolare e salvare ciascuna
trasformazione nidificata da parte di Compose.
Ad esempio, il seguente codice applica sia una traslazione sia 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 ) } }
Operazioni di disegno comuni
Disegna testo
Per disegnare un testo in Compose, in genere puoi utilizzare l'elemento componibile Text
. Tuttavia,
se ti trovi in un elemento DrawScope
o vuoi disegnare il testo manualmente 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") }
Misurare il testo
Il disegno del testo funziona in modo un po' diverso dagli altri comandi di disegno. Normalmente, assegna al comando di disegno le dimensioni (larghezza e altezza) per disegnare la forma/l'immagine. Con il testo, ci sono alcuni parametri che controllano la dimensione del testo visualizzato, come dimensione del carattere, carattere, legature e spaziatura tra le lettere.
Con Scrivi, puoi utilizzare una TextMeasurer
per ottenere l'accesso alle dimensioni misurate del testo, in base ai fattori elencati in precedenza. Se vuoi tracciare 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 nel testo:
Se modifichi i vincoli, le dimensioni del carattere o qualsiasi proprietà che influisca sulle dimensioni misurate, viene riportata una nuova dimensione. Puoi impostare una dimensione fissa per width
e height
; il testo segue quindi il set TextOverflow
. Ad esempio, il seguente codice esegue il rendering del testo a 1⁄3 dell'altezza e a 1⁄3 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 una ImageBitmap
con DrawScope
, carica l'immagine utilizzando ImageBitmap.imageResource()
, quindi chiama drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
Disegnare forme di base
In DrawScope
sono disponibili 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 |
Uscita |
Disegna percorso
Un percorso è una serie di istruzioni matematiche che, una volta eseguito, generano un disegno. DrawScope
può tracciare 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 a Canvas
oggetto in corso...
Con DrawScope
non hai accesso diretto a un oggetto Canvas
. Puoi utilizzare DrawScope.drawIntoCanvas()
per ottenere l'accesso all'oggetto Canvas
stesso su cui puoi chiamare le funzioni.
Ad esempio, se vuoi disegnare un elemento Drawable
personalizzato sul canvas, puoi accedere al 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 saperne di più su Disegno in Compose, dai un'occhiata alle seguenti risorse:
- Modificatori grafici: scopri i diversi tipi di modificatori del disegno.
- Pennello: scopri come personalizzare il colore 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.
- JetLagged Sample: un esempio di composizione che mostra come disegnare un grafico personalizzato.
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori grafici
- Elementi grafici in Compose
- Linee di allineamento in Jetpack Compose