Element Brush
w sekcji Utwórz opisuje sposób rysowania elementów na ekranie.Określa on kolory, które zostaną rysowane w obszarze rysowania (tj. okrąg, kwadrat, ścieżkę). Dostępnych jest kilka wbudowanych pędzli, które przydają się do rysowania, np. LinearGradient
, RadialGradient
i zwykły pędzel SolidColor
.
Aby zastosować styl malowania do rysowanych treści, możesz używać pędzli z elementami Modifier.background()
, TextStyle
i DrawScope
.
Na przykład do narysowania okręgu w aplikacji
DrawScope
można użyć pędzla poziomego gradientu:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
Pędzle w kolorze gradientu
Wbudowanych jest wiele pędzli gradientu, których można używać do uzyskiwania różnych efektów gradientu. Te pędzle pozwalają określić listę kolorów, z których chcesz utworzyć gradient.
Lista dostępnych pędzli z gradientem i odpowiadające im dane wyjściowe:
Rodzaj pędzla gradientowego | Odpowiedź |
---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
Uwaga: aby zapewnić płynne przejście między kolorami, ustaw ostatni kolor na kolor początkowy. |
|
Brush.radialGradient(colorList) |
Zmień rozkład kolorów za pomocą funkcji colorStops
Aby dostosować sposób wyświetlania kolorów w gradiencie, możesz dostosować wartość colorStops
w każdym z nich. Wartość colorStops
należy podawać jako ułamek z zakresu od 0 do 1. Jeśli podasz wartość większą niż 1, kolory te nie będą renderowane w ramach gradientu.
Możesz skonfigurować różne ilości kolorów, 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 w podanym przesunięciach, zgodnie z wartością pary colorStop
. Kolor jest mniej żółty niż czerwony i niebieski.
Powtórz wzór w aplikacji TileMode
Każdy pędzel gradientu ma opcję ustawienia TileMode
. Jeśli nie ustawisz początku i końca gradientu, możesz nie zauważyć elementu TileMode
, ponieważ domyślnie wypełni on cały obszar. TileMode
umieszcza gradient obok siebie tylko wtedy,
gdy rozmiar obszaru jest większy niż rozmiar pędzla.
Ten kod powtórzy wzorzec gradientu 4 razy, ponieważ endX
ma wartość 50.dp
, a rozmiar – 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 z opisem działania różnych trybów kafelków w powyższym przykładzie HorizontalGradient
:
Tryb kafelków | Odpowiedź |
---|---|
TileMode.Repeated : krawędź powtarza się od ostatniego koloru do pierwszego. |
|
TileMode.Mirror : krawędź jest powielana od ostatniego koloru do pierwszego. |
|
TileMode.Clamp : krawędź jest przycięta do ostatecznego koloru. Następnie maluje najbliższy kolor pozostałym regionowi. |
|
TileMode.Decal : renderowanie do wartości granicznych. TileMode.Decal wykorzystuje przezroczystą czerń, aby próbkować treści poza pierwotnymi granicami, a TileMode.Clamp próbkuje kolor krawędzi. |
Funkcja TileMode
działa w podobny sposób w przypadku innych gradientów kierunkowych. Różnica polega na tym, gdzie następuje powtarzanie.
Zmień rozmiar pędzla
Jeśli znasz rozmiar obszaru, w którym zostanie narysowany pędzel, możesz ustawić kafelek endX
, tak jak w sekcji TileMode
. Jeśli znajdujesz się w lokalizacji DrawScope
, możesz użyć jej właściwości size
, aby poznać wielkość obszaru.
Jeśli nie znasz rozmiaru obszaru rysowania (np. jeśli element Brush
jest przypisany do tekstu), możesz rozszerzyć zakres Shader
i użyć rozmiaru obszaru rysowania w funkcji createShader
.
W tym przykładzie podziel rozmiar przez 4, aby powtórzyć wzorzec 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 dowolnego innego gradientu, np. gradientu promieniowego. Jeśli nie określisz rozmiaru i środka, gradient zajmie pełne granice obszaru DrawScope
, a sam środek gradientu promieniowego zajmie środek tych granic: DrawScope
. W ten sposób środek gradientu promieniowego wyświetla się po środku mniejszego wymiaru (szerokości lub wysokości):
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
Po zmianie gradientu promieniowego w celu ustawienia rozmiaru promienia na wymiar maksymalny widać, że zapewnia to lepszy efekt gradientu promieniowego:
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 cienia jest określany w miejscu, w którym jest wywoływany. Domyślnie Brush
przeniesie wewnętrznie element Shader
, jeśli jego rozmiar będzie inny niż przy ostatnim utworzonym elemencie Brush
lub jeśli zmieni się obiekt stanu używany do utworzenia programu do cieniowania.
Poniższy kod powoduje utworzenie cieniowania 3 razy o różnych rozmiarach, gdy 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ć ImageBitmap jako Brush
, załaduj 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 można stosować do różnych rodzajów rysunków: tła, tekstu i obszaru roboczego. Uzyskane wyniki:
Zwróć uwagę, że tekst jest teraz renderowany za pomocą elementu ImageBitmap
do malowania pikseli w tekście.
Przykład zaawansowany: pędzel niestandardowy
Pędzel AGSL RuntimeShader
AGSL oferuje podzbiór funkcji Shadera w GLSL. Shadery można pisać w AGSL, a potem używać pędzla w tworzeniu wiadomości.
Aby utworzyć pędzel do cieniowania, najpierw zdefiniuj pędzel do cieniowania jako ciąg cieniowania 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 kreator stosuje 2 kolory wejściowe, oblicza odległość od lewego dolnego rogu obszaru rysowania (vec2(0, 1)
) i wykona mix
między 2 kolorami na podstawie odległości. Powoduje to efekt gradientu.
Następnie utwórz Pędzel cienia i ustaw uniformy dla elementu resolution
, czyli rozmiaru obszaru rysowania, oraz elementów color
i color2
, których chcesz używać jako danych wejściowych do 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 jego uruchomieniu zobaczysz wyrenderowane na ekranie te elementy:
Warto zauważyć, że cieniowanie to o wiele więcej niż gradienty – wszystkie obliczenia opierają się na obliczeniach matematycznych. Więcej informacji o AGSL znajdziesz w dokumentacji AGSL.
Dodatkowe materiały
Więcej przykładów użycia pędzla w tworzeniu wiadomości znajdziesz w tych materiałach:
- Animowanie koloru tekstu pędzla w sekcji Utwórz 🖌️
- Niestandardowe grafiki i układy w tworzeniu wiadomości – Android Dev Summit 2022
- JetLagged Sample – RuntimeShader Brush
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy JavaScript jest wyłączony
- Modyfikatory graficzne
- Grafika w obszarze tworzenia wiadomości
- Styl tekstu