Brush
w Compose opisuje sposób rysowania czegoś na ekranie: określa kolory, które są rysowane w obszarze rysowania (np. koło, kwadrat, ścieżka). Dostępnych jest kilka wbudowanych pędzli, które przydają się do rysowania, np. LinearGradient
, RadialGradient
lub zwykły pędzel SolidColor
.
Pędzle można stosować w przypadku wywołań rysowania Modifier.background()
, TextStyle
lub DrawScope
, aby zastosować styl malowania do rysowanej treści.
Na przykład pędzla z poziomym gradientem można użyć do narysowania okręgu w DrawScope
:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )

Pędzle gradientowe
Istnieje wiele wbudowanych pędzli gradientowych, które można wykorzystać do uzyskania różnych efektów gradientu. Te pędzle umożliwiają określenie listy kolorów, z których chcesz utworzyć gradient.
Lista dostępnych pędzli gradientowych i odpowiadających im wyników:
Typ pędzla gradientowego | Urządzenie wyjściowe |
---|---|
Brush.horizontalGradient(colorList) |
![]() |
Brush.linearGradient(colorList) |
![]() |
Brush.verticalGradient(colorList) |
![]() |
Brush.sweepGradient(colorList)
Uwaga: aby uzyskać płynne przejście między kolorami, ustaw ostatni kolor jako kolor początkowy. |
![]() |
Brush.radialGradient(colorList) |
![]() |
Zmień rozkład kolorów za pomocą colorStops
Aby dostosować wygląd kolorów w gradiencie, możesz zmienić colorStops
wartość każdego z nich. colorStops
należy podać jako ułamek z zakresu od 0 do 1. Wartości większe niż 1 spowodują, że te kolory nie będą renderowane jako część gradientu.
Możesz skonfigurować punkty kolorów tak, aby zawierały różne ilości, np. mniej lub więcej jednego koloru:
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)) )
Kolory są rozproszone z podanym przesunięciem, zgodnie z definicją w colorStop
parze, mniej żółte niż czerwone i niebieskie.

Powtórz wzór za pomocą TileMode
Każdy pędzel gradientowy ma opcję ustawienia na nim TileMode
. Jeśli nie ustawisz początku i końca gradientu, możesz nie zauważyć ikony TileMode
, ponieważ domyślnie wypełni ona cały obszar. Wzór TileMode
będzie powielany tylko wtedy, gdy rozmiar obszaru jest większy niż rozmiar pędzla.
Poniższy kod powtórzy wzór gradientu 4 razy, ponieważ endX
ma wartość 50.dp
, a rozmiar ma wartość 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 ) ) )
W tabeli poniżej znajdziesz szczegółowe informacje o tym, jak poszczególne tryby kafelków działają w przypadku HorizontalGradient
przykładu powyżej:
Tryb kafelków | Urządzenie wyjściowe |
---|---|
TileMode.Repeated : krawędź jest powtarzana od ostatniego do pierwszego koloru. |
![]() |
TileMode.Mirror : krawędź jest odzwierciedlana od ostatniego koloru do pierwszego. |
![]() |
TileMode.Clamp : krawędź jest przycinana do koloru końcowego. Następnie pomaluje pozostałą część regionu najbliższym kolorem. |
![]() |
TileMode.Decal : renderowanie tylko do rozmiaru granic. TileMode.Decal wykorzystuje przezroczystą czerń do próbkowania treści poza oryginalnymi granicami, a TileMode.Clamp próbkuje kolor krawędzi. |
![]() |
TileMode
działa podobnie w przypadku innych gradientów kierunkowych, z tą różnicą, że powtórzenie występuje w innym kierunku.
Zmiana rozmiaru pędzla
Jeśli znasz rozmiar obszaru, w którym będzie rysowany pędzel, możesz ustawić kafel endX
, jak pokazano powyżej w sekcji TileMode
. Jeśli znajdujesz się w DrawScope
, możesz użyć właściwości size
, aby uzyskać rozmiar obszaru.
Jeśli nie znasz rozmiaru obszaru rysowania (np. jeśli do elementu Brush
przypisany jest tekst), możesz rozszerzyć Shader
i wykorzystać rozmiar obszaru rysowania w funkcji createShader
.
W tym przykładzie podziel rozmiar przez 4, aby powtórzyć wzór 4 razy:
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) )

Możesz też zmienić rozmiar pędzla w przypadku innych gradientów, np. gradientów promieniowych. Jeśli nie określisz rozmiaru i środka, gradient zajmie całą przestrzeń DrawScope
, a środek gradientu promieniowego będzie domyślnie znajdować się w środku przestrzeni DrawScope
. W rezultacie środek gradientu promienistego będzie się znajdować na środku mniejszego wymiaru (szerokości lub wysokości):
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )

Gdy zmienisz gradient promienisty, aby ustawić maksymalny rozmiar promienia, zobaczysz, że daje on lepszy efekt:
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) )

Warto zauważyć, że rzeczywisty rozmiar przekazywany do tworzenia cieniowania jest określany na podstawie miejsca, z którego jest wywoływany. Domyślnie funkcja Brush
wewnętrznie ponownie przydzieli pamięć Shader
, jeśli rozmiar będzie inny niż ostatnia kreacja Brush
lub jeśli obiekt stanu użyty do utworzenia shadera ulegnie zmianie.
Poniższy kod tworzy shader 3 razy z różnymi rozmiarami, ponieważ zmienia się rozmiar obszaru rysowania:
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) } } } )
Używanie obrazu jako pędzla
Aby użyć obiektu ImageBitmap jako Brush
, wczytaj obraz jako ImageBitmap
i utwórz pędzel 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))
Pędzel jest stosowany w przypadku kilku różnych typów rysowania: tła, tekstu i obszaru rysowania. Wynik będzie wyglądać tak:

Zwróć uwagę, że tekst jest teraz renderowany za pomocą parametru ImageBitmap
, który służy do rysowania pikseli tekstu.
Zaawansowany przykład: pędzel niestandardowy
Pędzel AGSL RuntimeShader
AGSL oferuje podzbiór funkcji cieniowania GLSL. Shadery można pisać w języku AGSL i używać ich z pędzlem w Compose.
Aby utworzyć pędzel Shader, najpierw zdefiniuj Shader jako ciąg znaków Shadera 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()
Powyższy shader przyjmuje 2 kolory wejściowe, oblicza odległość od lewego dolnego rogu (vec2(0, 1)
) obszaru rysowania i wykonuje mix
między tymi 2 kolorami na podstawie odległości. Daje to efekt gradientu.
Następnie utwórz pędzel cieniujący i ustaw zmienne jednolite dla resolution
– rozmiaru obszaru rysowania oraz color
i color2
, które chcesz wykorzystać jako dane wejściowe dla niestandardowego gradientu:
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) ) }
Po uruchomieniu tego kodu na ekranie zobaczysz:

Warto zauważyć, że za pomocą shaderów można robić znacznie więcej niż tylko gradienty, ponieważ wszystko opiera się na obliczeniach matematycznych. Więcej informacji o AGSL znajdziesz w dokumentacji tego języka.
Dodatkowe materiały
Więcej przykładów użycia klasy Brush w Compose znajdziesz w tych materiałach:
- Animowanie pędzla Kolorowanie tekstu w Compose 🖌️
- Niestandardowe grafiki i układy w Compose – Android Dev Summit 2022
- JetLagged Sample - RuntimeShader Brush
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony.
- Modyfikatory grafiki
- Grafika w komponowaniu
- Styl tekstu