Molte app devono essere in grado di controllare con precisione ciò che viene disegnato sullo schermo. Potrebbe trattarsi di un semplice riquadro o cerchio sullo schermo nel punto giusto oppure di 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 è utilizzare modificatori come
Modifier.drawWithContent,
Modifier.drawBehind, e
Modifier.drawWithCache.
Ad esempio, per disegnare qualcosa dietro il tuo componibile, 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 componibile che disegni, puoi utilizzare il
Canvas componibile. Il componibile Canvas è un
wrapper pratico per Modifier.drawBehind. Inserisci 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 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
vengono fornite dai valori dei parametri predefiniti. I parametri predefiniti in genere posizionano l'elemento nel punto [0, 0] sul canvas e forniscono una size predefinita 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]) è il pixel più in alto a sinistra nell'area di disegno. x aumenta man mano che si sposta a 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 di
l'area del canvas all'angolo in basso a sinistra, puoi utilizzare la
DrawScope.drawLine() funzione 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 modificare la posizione o la modalità di esecuzione dei comandi di disegno.
Scala
Utilizza
DrawScope.scale()
per aumentare le dimensioni delle operazioni di disegno di un fattore. Le 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, 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 ) } }
rotate() per applicare una rotazione all'ambito di disegno corrente, che ruota il rettangolo di 45 gradi.
Interno
Utilizza DrawScope.inset() per regolare i parametri predefiniti dell'oggetto corrente
DrawScope, modificando i limiti di 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 effettivamente il padding ai comandi di disegno:
Più trasformazioni
Per applicare più trasformazioni ai disegni, utilizza la
DrawScope.withTransform() funzione, 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 a singole trasformazioni, perché tutte le trasformazioni vengono eseguite insieme in una singola operazione, anziché dover calcolare e salvare ogni trasformazione nidificata.
Ad esempio, il seguente codice applica sia una traduzione 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 ) } }
withTransform per applicare sia una rotazione sia una traduzione, ruotando il rettangolo e spostandolo a sinistra.Operazioni di disegno comuni
Disegna testo
Per disegnare testo in Compose, in genere puoi utilizzare il componibile Text. Tuttavia,
se ti trovi in un DrawScope o vuoi disegnare il testo manualmente con
la personalizzazione, puoi utilizzare il
DrawScope.drawText()
metodo.
Per disegnare 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 disegno del testo funziona in modo leggermente diverso rispetto ad altri comandi di disegno. In genere, al comando di disegno vengono assegnate le dimensioni (larghezza e altezza) con cui disegnare la forma/l'immagine. Con il testo, esistono alcuni parametri che controllano le dimensioni del testo sottoposto a rendering, come le dimensioni del carattere, il carattere, le legature e la 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 regolazione 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
e height, dopodiché il testo segue l'oggetto TextOverflow impostato. Ad
esempio, il seguente codice esegue il rendering del testo in ⅓ dell'altezza e ⅓ della larghezza
dell'area del 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.Disegna forme di base
Esistono molte funzioni di disegno di forme su DrawScope. 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.
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 ottenere
accesso all'oggetto Canvas stesso su cui puoi chiamare le funzioni.
Ad esempio, se hai un Drawable personalizzato che vuoi disegnare sul
canvas, puoi accedere al canvas e chiamare Drawable#draw(), passando l'
Canvas oggetto:
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 sul disegno in Compose, consulta le seguenti risorse:
- Modificatori grafici: scopri i diversi tipi di modificatori di disegno.
- Brush: scopri come personalizzare il disegno dei 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 Compose che mostra come disegnare un grafico personalizzato.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori grafici
- Grafica in Compose
- Linee di allineamento in Jetpack Compose