Un Brush in Compose descrive come viene disegnato qualcosa sullo schermo: determina i colori disegnati nell'area di disegno (ad es. un cerchio, un quadrato, un percorso). Esistono alcuni pennelli integrati utili per disegnare,
come LinearGradient, RadialGradient o un semplice
SolidColor pennello.
I pennelli possono essere utilizzati con Modifier.background(), TextStyle o
DrawScope chiamate di disegno per applicare lo stile di pittura ai contenuti
disegnati.
Ad esempio, un pennello a sfumatura orizzontale può essere applicato al disegno di un cerchio in DrawScope:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
Pennelli a sfumatura
Esistono molti pennelli a sfumatura integrati che possono essere utilizzati per ottenere diversi effetti di sfumatura. Questi pennelli ti consentono di specificare l'elenco dei colori da cui vuoi creare una sfumatura.
Un elenco dei pennelli a sfumatura disponibili e del relativo output:
| Tipo di pennello a sfumatura | Output |
|---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
Nota: per ottenere una transizione graduale tra i colori, imposta l'ultimo colore sul colore iniziale. |
|
Brush.radialGradient(colorList) |
|
Modificare la distribuzione dei colori con colorStops
Per personalizzare l'aspetto dei colori nella sfumatura, puoi modificare il valore colorStops per ciascuno di essi. colorStops deve essere specificato come frazione, compresa tra 0 e 1. I valori maggiori di 1 comporteranno il mancato rendering di questi colori come parte della sfumatura.
Puoi configurare le interruzioni di colore in modo che abbiano quantità diverse, ad esempio meno o più di un colore:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) Box( modifier = Modifier .requiredSize(200.dp) .background(Brush.horizontalGradient(colorStops = colorStops)) )
I colori sono dispersi all'offset fornito come definito nella coppia colorStop, meno giallo che rosso e blu.
Ripetere un pattern con TileMode
Ogni pennello a sfumatura ha la possibilità di impostare un TileMode. Potresti non notare TileMode se non hai impostato un inizio e una fine per la sfumatura, perché per impostazione predefinita riempirà l'intera area. Un TileMode affiancherà la sfumatura solo se le dimensioni dell'area sono maggiori delle dimensioni del pennello.
Il seguente codice ripeterà il pattern di sfumatura 4 volte, poiché endX è impostato su 50.dp e le dimensioni sono impostate su 200.dp:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val tileSize = with(LocalDensity.current) { 50.dp.toPx() } Box( modifier = Modifier .requiredSize(200.dp) .background( Brush.horizontalGradient( listColors, endX = tileSize, tileMode = TileMode.Repeated ) ) )
Di seguito è riportata una tabella che descrive in dettaglio le diverse modalità di affiancamento per l'esempio HorizontalGradient riportato sopra:
| TileMode | Output |
|---|---|
TileMode.Repeated: il bordo viene ripetuto dall'ultimo colore al primo. |
|
TileMode.Mirror: il bordo viene riflesso dall'ultimo colore al primo. |
|
TileMode.Clamp: il bordo viene bloccato sul colore finale. Quindi, dipinge il colore più vicino per il resto della regione. |
|
TileMode.Decal: esegui il rendering solo fino alle dimensioni dei limiti. TileMode.Decal utilizza il nero trasparente per campionare i contenuti al di fuori dei limiti originali, mentre TileMode.Clamp campiona il colore del bordo. |
|
TileMode funziona in modo simile per le altre sfumature direzionali, con la differenza che la ripetizione avviene in direzione diversa.
Modificare le dimensioni del pennello
Se conosci le dimensioni dell'area in cui verrà disegnato il pennello, puoi impostare endX del riquadro come abbiamo visto sopra nella sezione TileMode. Se ti trovi in
un DrawScope, puoi utilizzare la proprietà size per ottenere le dimensioni dell'area.
Se non conosci le dimensioni dell'area di disegno (ad esempio se il
Brush è assegnato a Text), puoi estendere Shader e utilizzare le dimensioni dell’area di disegno nella funzione createShader.
In questo esempio, dividi le dimensioni per 4 per ripetere il pattern 4 volte:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val customBrush = remember { object : ShaderBrush() { override fun createShader(size: Size): Shader { return LinearGradientShader( colors = listColors, from = Offset.Zero, to = Offset(size.width / 4f, 0f), tileMode = TileMode.Mirror ) } } } Box( modifier = Modifier .requiredSize(200.dp) .background(customBrush) )
Puoi anche modificare le dimensioni del pennello di qualsiasi altra sfumatura, ad esempio le sfumature radiali. Se non specifichi una dimensione e un centro, la sfumatura occuperà i limiti completi di DrawScope e il centro della sfumatura radiale verrà impostato per impostazione predefinita al centro dei limiti di DrawScope. Di conseguenza, il centro della sfumatura radiale appare come il centro della dimensione più piccola (larghezza o altezza):
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
Quando la sfumatura radiale viene modificata per impostare le dimensioni del raggio sulla dimensione massima, puoi notare che produce un effetto di sfumatura radiale migliore:
val largeRadialGradient = object : ShaderBrush() { override fun createShader(size: Size): Shader { val biggerDimension = maxOf(size.height, size.width) return RadialGradientShader( colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)), center = size.center, radius = biggerDimension / 2f, colorStops = listOf(0f, 0.95f) ) } } Box( modifier = Modifier .fillMaxSize() .background(largeRadialGradient) )
È importante notare che le dimensioni effettive passate alla creazione dello shader sono determinate dal punto in cui viene richiamato. Per impostazione predefinita, Brush rialloca internamente il relativo Shader se le dimensioni sono diverse dall'ultima creazione di Brush o se è stato modificato un oggetto di stato utilizzato nella creazione dello shader.
Il seguente codice crea lo shader tre volte con dimensioni diverse, man mano che cambiano le dimensioni dell'area di disegno:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) val brush = Brush.horizontalGradient(colorStops = colorStops) Box( modifier = Modifier .requiredSize(200.dp) .drawBehind { drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area inset(10f) { /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the inset scope reduces the drawing area by 10 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) inset(5f) { /* will allocate a shader to occupy the 170 x 170 dp drawing area as the inset scope reduces the drawing area by 5 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) } } } )
Utilizzare un'immagine come pennello
Per utilizzare un ImageBitmap come Brush, carica l'immagine come un ImageBitmap,
e crea un pennello ImageShader:
val imageBrush = ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog))) // Use ImageShader Brush with background Box( modifier = Modifier .requiredSize(200.dp) .background(imageBrush) ) // Use ImageShader Brush with TextStyle Text( text = "Hello Android!", style = TextStyle( brush = imageBrush, fontWeight = FontWeight.ExtraBold, fontSize = 36.sp ) ) // Use ImageShader Brush with DrawScope#drawCircle() Canvas(onDraw = { drawCircle(imageBrush) }, modifier = Modifier.size(200.dp))
Il pennello viene applicato a diversi tipi di disegno: uno sfondo, il testo e la tela. Viene generato il seguente output:
Tieni presente che ora anche il testo viene sottoposto a rendering utilizzando ImageBitmap per dipingere i pixel del testo.
Esempio avanzato: pennello personalizzato
Pennello RuntimeShader AGSL
AGSL offre un sottoinsieme di funzionalità dello shader GLSL. Gli shader possono essere scritti in AGSL e utilizzati con un pennello in Compose.
Per creare un pennello shader, definisci prima lo shader come stringa dello shader AGSL:
@Language("AGSL") val CUSTOM_SHADER = """ uniform float2 resolution; layout(color) uniform half4 color; layout(color) uniform half4 color2; half4 main(in float2 fragCoord) { float2 uv = fragCoord/resolution.xy; float mixValue = distance(uv, vec2(0, 1)); return mix(color, color2, mixValue); } """.trimIndent()
Lo shader riportato sopra accetta due colori di input, calcola la distanza dall'angolo in basso a sinistra (vec2(0, 1)) dell'area di disegno ed esegue un mix tra i due colori in base alla distanza. In questo modo viene prodotto un effetto di sfumatura.
Quindi, crea il pennello shader e imposta le uniformi per resolution (le dimensioni dell'area di disegno) e i color e color2 che vuoi utilizzare come input per la sfumatura personalizzata:
val Coral = Color(0xFFF3A397) val LightYellow = Color(0xFFF8EE94) @RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable @Preview fun ShaderBrushExample() { Box( modifier = Modifier .drawWithCache { val shader = RuntimeShader(CUSTOM_SHADER) val shaderBrush = ShaderBrush(shader) shader.setFloatUniform("resolution", size.width, size.height) onDrawBehind { shader.setColorUniform( "color", android.graphics.Color.valueOf( LightYellow.red, LightYellow.green, LightYellow .blue, LightYellow.alpha ) ) shader.setColorUniform( "color2", android.graphics.Color.valueOf( Coral.red, Coral.green, Coral.blue, Coral.alpha ) ) drawRect(shaderBrush) } } .fillMaxWidth() .height(200.dp) ) }
Eseguendo questo codice, puoi vedere il seguente rendering sullo schermo:
È importante notare che puoi fare molto di più con gli shader rispetto alle semplici sfumature, poiché si tratta di calcoli basati sulla matematica. Per saperne di più su AGSL, consulta la documentazione di AGSL.
Risorse aggiuntive
Per altri esempi di utilizzo di Brush in Compose, consulta le seguenti risorse:
- Animare la colorazione del testo del pennello in Compose 🖌️
- Grafica e layout personalizzati in Compose - Android Dev Summit 2022
- Esempio di JetLagged - Pennello RuntimeShader
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori grafici
- Grafica in Compose
- Applicare uno stile al testo