Ein Brush
in „Schreiben“ beschreibt, wie etwas auf dem Bildschirm gezeichnet wird:
bestimmt die Farbe(n), die im Zeichenbereich gezeichnet werden (d.h. ein Kreis,
Quadrat, Pfad). Es gibt einige integrierte Pinsel, die zum Zeichnen
wie LinearGradient
, RadialGradient
oder eine einfache
SolidColor
-Pinsel
Pinsel können mit den Zeichenaufrufen Modifier.background()
, TextStyle
oder DrawScope
verwendet werden, um den Malstil auf die gezeichneten Inhalte anzuwenden.
Mit einem horizontalen Farbverlauf-Pinsel können Sie zum Beispiel einen Kreis in
DrawScope
:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
Farbverlaufspinsel
Es gibt viele integrierte Farbverlaufs-Pinsel, mit denen Sie verschiedene Farbverlaufseffekte erzielen können. Mit diesen Pinseln können Sie eine Liste der Farben festlegen, aus dem Sie einen Farbverlauf erstellen möchten.
Eine Liste der verfügbaren Farbverlaufspinsel und ihrer entsprechenden Ausgabe:
Art des Farbverlaufs-Pinsels | Ausgabe |
---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
Hinweis: Legen Sie für die letzte Farbe die Startfarbe fest, um einen gleichmäßigen Übergang zwischen den Farben zu erzielen. |
|
Brush.radialGradient(colorList) |
Farbverteilung mit colorStops
ändern
Um die Darstellung der Farben im Farbverlauf anzupassen, können Sie
colorStops
Wert pro Element. colorStops
muss als Bruch angegeben werden,
zwischen 0 und 1 liegen. Werte über 1 führen dazu, dass diese Farben nicht als Teil des Farbverlaufs gerendert werden.
Sie können die Farbstopps so konfigurieren, dass sie unterschiedlich groß sind, z. B. weniger oder mehrere Farben:
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 sind mit dem angegebenen Versatz verteilt, wie in den colorStop
definiert.
weniger Gelb als Rot und Blau.
Muster mit TileMode
wiederholen
Für jeden Farbverlauf kann ein TileMode
festgelegt werden. Sie dürfen nicht
Wenn Sie kein Anfang und Ende für den Farbverlauf festgelegt haben, sehen Sie TileMode
.
füllt sie standardmäßig den gesamten Bereich aus. Mit TileMode
wird nur der Farbverlauf in Kacheln umgewandelt.
wenn der Bereich größer als der Pinsel ist.
Mit dem folgenden Code wird das Farbverlaufsmuster viermal wiederholt, da endX
gleich
auf 50.dp
und die Größe auf 200.dp
festgelegt:
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 sehen Sie, welche Funktion die verschiedenen Kachelmodi
HorizontalGradient
-Beispiel oben:
Kachelmodus | Ausgabe |
---|---|
TileMode.Repeated : Der Rand wird von der letzten Farbe zur ersten wiederholt. |
|
TileMode.Mirror : Der Rand wird von der letzten Farbe zur ersten gespiegelt. |
|
TileMode.Clamp : Der Rand wird an die endgültige Farbe gebunden. Dann wird die Farbe für den Rest der Region verwendet. |
|
TileMode.Decal : Wird nur bis zur Größe der Grenzen gerendert. Bei TileMode.Decal wird transparentes Schwarz verwendet, um Inhalte außerhalb der ursprünglichen Grenzen zu erfassen, während bei TileMode.Clamp die Randfarbe verwendet wird. |
TileMode
funktioniert ähnlich für die anderen Richtungsverläufe, den
die Richtung der Wiederholung.
Pinselgröße ändern
Wenn Sie die Größe des Bereichs kennen, in dem Ihr Pinsel gezeichnet werden soll,
Legen Sie die Kachel endX
fest, wie wir oben im Abschnitt TileMode
gesehen haben. In diesem Fall
eine DrawScope
haben, können Sie ihre size
-Eigenschaft verwenden, um die Größe des Bereichs abzurufen.
Wenn Sie die Größe des Zeichenbereichs nicht kennen (z. B. wenn Brush
dem Text zugewiesen ist), können Sie Shader
erweitern und die Größe des Zeichenbereichs in der Funktion createShader
verwenden.
In diesem Beispiel teilen Sie die Größe durch 4, 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 jedes anderen Farbverlaufs ändern, z. B. den radialen Farbverlauf.
Farbverläufe. Wenn Sie keine Größe und Mitte angeben, nimmt der Farbverlauf
vollständige Grenzen von DrawScope
und den Mittelpunkt der Standardeinstellungen für den radialen Farbverlauf
bis zum Mittelpunkt der DrawScope
-Grenzen. Daraus ergibt sich die
Mittelpunkt, der als Mittelpunkt der kleineren Dimension (entweder Breite oder
Höhe):
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
Wenn der radiale Farbverlauf geändert wird, um die Radiusgröße auf die maximale Dimension festzulegen, sehen Sie, dass es einen besseren radialen Farbverlaufseffekt erzeugt:
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 bei der Erstellung des
Shader wird von dem Ort ermittelt, an dem er aufgerufen wird. Standardmäßig wird Shader
von Brush
intern neu zugewiesen, wenn sich die Größe von der letzten Erstellung von Brush
unterscheidet oder sich ein Statusobjekt geändert hat, das bei der Erstellung des Shaders verwendet wurde.
Mit dem folgenden Code wird der Shader dreimal mit unterschiedlichen wenn 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) } } } )
Bilder als Pinsel verwenden
Um eine ImageBitmap als Brush
zu verwenden, laden Sie das Bild als ImageBitmap
hoch.
und erstelle 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 Zeichenarten angewendet: auf den Hintergrund, den Text und Canvas. Dadurch wird Folgendes ausgegeben:
Beachten Sie, dass der Text jetzt ebenfalls mit ImageBitmap
gerendert wird, um das
Pixel für den Text.
Beispiel für Fortgeschrittene: Benutzerdefinierter Pinsel
AGSL-Pinsel "RuntimeShader
"
AGSL bietet einen Teil der GLSL-Shader-Funktionen an. Shader können in AGSL geschrieben und mit einem Pinsel in Compose verwendet.
Um einen Shader-Pinsel zu erstellen, definieren Sie zuerst den Shader als AGSL-Shaderstring:
@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 und berechnet den Abstand vom unteren Rand
links (vec2(0, 1)
) des Zeichenbereichs und führt ein mix
zwischen den beiden Farben
basierend auf der Entfernung. Dadurch entsteht ein Farbverlaufseffekt.
Erstelle dann den Shader-Pinsel und lege die Uniformen für resolution
fest – die Größe
des Zeichenbereichs und die color
und color2
, die Sie als Eingabe für
Ihren benutzerdefinierten Farbverlauf:
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 diesen Befehl ausführen, sehen Sie Folgendes auf dem Bildschirm:
Mit Shadern lassen sich neben Farbverläufen noch viel mehr. weil das alles mathematisch basierte Berechnungen sind. Weitere Informationen zu AGSL finden Sie in der AGSL-Dokumentation
Weitere Informationen
Weitere Beispiele zur Verwendung von Prush in Compose finden Sie in den folgenden Ressourcen:
- Pinselfarbe in „Schreiben“ animieren 🖌️
- Benutzerdefinierte Grafiken und Layouts in Compose – Android Dev Summit 2022
- JetLagged-Beispiel – RuntimeShader Brush
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Grafikmodifikatoren
- Grafiken in „Compose“
- Text formatieren