Ein Brush in Compose beschreibt, wie etwas auf dem Bildschirm gezeichnet wird: Es bestimmt die Farben, die im Zeichenbereich (z.B. Kreis, Quadrat, Pfad) gezeichnet werden. Es gibt einige integrierte Pinsel, die sich zum Zeichnen eignen, z. B. LinearGradient, RadialGradient oder ein einfacher SolidColor-Pinsel.
Pinsel können mit den Zeichenbefehlen Modifier.background(), TextStyle oder DrawScope verwendet werden, um den Malstil auf die gezeichneten Inhalte anzuwenden.
Beispielsweise kann ein horizontaler Farbverlaufspinsel zum Zeichnen eines Kreises in DrawScope verwendet werden:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
Verlaufspinsel
Es gibt viele integrierte Farbverlaufspinsel, mit denen sich verschiedene Farbverlaufseffekte erzielen lassen. Mit diesen Pinseln können Sie die Liste der Farben angeben, aus denen Sie einen Farbverlauf erstellen möchten.
Hier finden Sie eine Liste der verfügbaren Farbverlaufspinsel und der entsprechenden Ausgabe:
| Pinseltyp für Farbverlauf | Ausgabe |
|---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
Hinweis: Wenn Sie einen fließenden Übergang zwischen den Farben wünschen, legen Sie die letzte Farbe als Startfarbe fest. |
|
Brush.radialGradient(colorList) |
|
Farbverteilung mit colorStops ändern
Wenn Sie die Darstellung der Farben im Farbverlauf anpassen möchten, können Sie den Wert colorStops für jede Farbe ändern. colorStops sollte als Bruch zwischen 0 und 1 angegeben werden. Werte, die größer als 1 sind, führen dazu, dass diese Farben nicht als Teil des Farbverlaufs gerendert werden.
Sie können die Farbstopps so konfigurieren, dass sie unterschiedliche Anteile haben, z. B. weniger oder mehr von einer Farbe:
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)) )
Die Farben werden mit dem angegebenen Offset verteilt, wie im Paar colorStop definiert, weniger Gelb als Rot und Blau.
Muster mit TileMode wiederholen
Für jeden Farbverlaufspinsel kann ein TileMode festgelegt werden. Wenn Sie keinen Start- und Endpunkt für den Farbverlauf festgelegt haben, wird der gesamte Bereich ausgefüllt und Sie sehen TileMode möglicherweise nicht. Bei einem TileMode wird der Farbverlauf nur dann gekachelt, wenn die Größe des Bereichs größer als die Pinselgröße ist.
Im folgenden Code wird das Verlaufsmuster viermal wiederholt, da endX auf 50.dp und die Größe auf 200.dp festgelegt ist:
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 ) ) )
In der folgenden Tabelle wird beschrieben, was die verschiedenen Kachelmodi für das obige HorizontalGradient-Beispiel bewirken:
| TileMode | Ausgabe |
|---|---|
TileMode.Repeated: Der Rand wird von der letzten zur ersten Farbe wiederholt. |
|
TileMode.Mirror: Die Kante wird von der letzten zur ersten Farbe gespiegelt. |
|
TileMode.Clamp: Der Rand wird auf die endgültige Farbe beschränkt. Anschließend wird die nächstgelegene Farbe für den Rest der Region verwendet. |
|
TileMode.Decal: Rendern nur bis zur Größe der Grenzen. TileMode.Decal nutzt transparentes Schwarz, um Inhalte außerhalb der ursprünglichen Grenzen zu erfassen, während TileMode.Clamp die Randfarbe erfasst. |
|
TileMode funktioniert bei den anderen Richtungsgradienten ähnlich. Der Unterschied besteht in der Richtung, in der die Wiederholung erfolgt.
Pinselgröße ändern
Wenn Sie die Größe des Bereichs kennen, in dem der Pinsel gezeichnet wird, können Sie die Kachel endX wie oben im Abschnitt TileMode beschrieben festlegen. Wenn Sie sich in einem DrawScope befinden, können Sie die Größe des Bereichs mit der Property size abrufen.
Wenn Sie die Größe des Zeichenbereichs nicht kennen (z. B. wenn Brush Text zugewiesen ist), können Sie Shader erweitern und die Größe des Zeichenbereichs in der Funktion createShader verwenden.
In diesem Beispiel wird die Größe durch 4 geteilt, um das Muster viermal zu wiederholen:
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) )
Sie können auch die Pinselgröße anderer Farbverläufe ändern, z. B. von radialen Farbverläufen. Wenn Sie keine Größe und keinen Mittelpunkt angeben, nimmt der Farbverlauf die gesamten Grenzen des DrawScope ein und der Mittelpunkt des radialen Farbverlaufs ist standardmäßig der Mittelpunkt der DrawScope-Grenzen. Dadurch wird der Mittelpunkt des radialen Farbverlaufs als Mittelpunkt der kleineren Dimension (entweder Breite oder Höhe) angezeigt:
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
Wenn der radiale Farbverlauf so geändert wird, dass die Radiusgröße auf die maximale Dimension festgelegt wird, ist der radiale Farbverlaufseffekt besser:
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) )
Die tatsächliche Größe, die an die Erstellung des Shaders übergeben wird, wird von der Stelle bestimmt, von der er aufgerufen wird. Standardmäßig wird Brush die Shader intern neu zuweisen, wenn die Größe von der letzten Erstellung von Brush abweicht oder wenn sich ein Zustandsobjekt geändert hat, das bei der Erstellung des Shaders verwendet wurde.
Mit dem folgenden Code wird der Shader dreimal mit unterschiedlichen Größen erstellt, da sich die Größe des Zeichenbereichs ändert:
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) } } } )
Bild als Pinsel verwenden
Wenn Sie eine ImageBitmap als Brush verwenden möchten, laden Sie das Bild als ImageBitmap und erstellen Sie einen ImageShader-Pinsel:
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))
Der Pinsel wird auf verschiedene Arten von Zeichnungen angewendet: einen Hintergrund, den Text und den Canvas. Dadurch wird Folgendes ausgegeben:
Der Text wird jetzt auch mit dem ImageBitmap gerendert, um die Pixel für den Text zu zeichnen.
Erweitertes Beispiel: Benutzerdefinierter Pinsel
AGSL-RuntimeShader-Pinsel
AGSL bietet einen Teil der GLSL-Shader-Funktionen. Shader können in AGSL geschrieben und mit einem Brush in Compose verwendet werden.
Wenn Sie einen Shader-Pinsel erstellen möchten, definieren Sie den Shader zuerst als AGSL-Shader-String:
@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()
Der obige Shader verwendet zwei Eingabefarben, berechnet den Abstand von der linken unteren Ecke (vec2(0, 1)) des Zeichenbereichs und führt basierend auf dem Abstand eine mix zwischen den beiden Farben durch. Dadurch entsteht ein Verlaufseffekt.
Erstellen Sie dann den Shader-Pinsel und legen Sie die Uniforms für resolution (die Größe des Zeichenbereichs) sowie die color und color2 fest, die Sie als Eingabe für Ihren benutzerdefinierten Farbverlauf verwenden möchten:
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) ) }
Wenn Sie dies ausführen, wird Folgendes auf dem Bildschirm angezeigt:
Mit Shadern können Sie viel mehr als nur Farbverläufe erstellen, da alles auf mathematischen Berechnungen basiert. Weitere Informationen zu AGSL finden Sie in der AGSL-Dokumentation.
Zusätzliche Ressourcen
Weitere Beispiele für die Verwendung von „Brush“ in Compose finden Sie in den folgenden Ressourcen:
- Textfärbung mit animiertem Pinsel in Compose 🖌️
- Benutzerdefinierte Grafiken und Layouts in Compose – Android Dev Summit 2022
- JetLagged-Beispiel – RuntimeShader-Pinsel
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafikmodifikatoren
- Grafiken in Compose
- Text formatieren