Compose 中的 Brush
描述了如何在屏幕上绘制内容:它决定了在绘制区域(即圆形、方形、路径)中绘制的颜色。有一些内置的画笔非常适合绘制,例如 LinearGradient
、RadialGradient
或纯色 SolidColor
画笔。
画笔可以与 Modifier.background()
、TextStyle
或 DrawScope
绘图调用一起使用,以将绘制样式应用于正在绘制的内容。
例如,水平渐变画笔可以应用于在 DrawScope
中绘制圆形
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )

渐变画笔
有许多内置的渐变画笔可用于实现不同的渐变效果。这些画笔允许您指定要从中创建渐变的颜色列表。
可用渐变画笔及其对应输出列表
渐变画笔类型 | 输出 |
---|---|
Brush.horizontalGradient(colorList) |
![]() |
Brush.linearGradient(colorList) |
![]() |
Brush.verticalGradient(colorList) |
![]() |
Brush.sweepGradient(colorList)
注意:为了获得平滑的颜色过渡,请将最后一种颜色设置为起始颜色。 |
![]() |
Brush.radialGradient(colorList) |
![]() |
使用 colorStops
更改颜色分布
要自定义颜色在渐变中的显示方式,您可以调整每个颜色的 colorStops
值。colorStops
应指定为分数,介于 0 和 1 之间。大于 1 的值将导致这些颜色不作为渐变的一部分进行渲染。
您可以配置色标以具有不同的量,例如更少或更多的一种颜色
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)) )
颜色按照 colorStop
对中定义的偏移量分散,黄色少于红色和蓝色。

使用 TileMode
重复图案
每个渐变画笔都可以选择设置 TileMode
。如果您没有为渐变设置开始和结束,您可能不会注意到 TileMode
,因为它将默认为填充整个区域。TileMode
只会在区域大小大于画笔大小时才平铺渐变。
以下代码将重复渐变图案 4 次,因为 endX
设置为 50.dp
,大小设置为 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 ) ) )
下表详细说明了上述 HorizontalGradient
示例的不同平铺模式的作用
TileMode | 输出 |
---|---|
TileMode.Repeated :边缘从最后一种颜色重复到第一种颜色。 |
![]() |
TileMode.Mirror :边缘从最后一种颜色镜像到第一种颜色。 |
![]() |
TileMode.Clamp :边缘被钳制到最终颜色。然后它将为区域的其余部分绘制最接近的颜色。 |
![]() |
TileMode.Decal :仅渲染到边界大小。 TileMode.Decal 利用透明黑色采样原始边界之外的内容,而 TileMode.Clamp 采样边缘颜色。 |
![]() |
TileMode
对其他方向的渐变也以类似的方式工作,区别在于重复发生的方向。
更改画笔大小
如果您知道画笔将被绘制的区域的大小,您可以像我们在 TileMode
部分中看到的那样设置平铺 endX
。如果您在 DrawScope
中,您可以使用其 size
属性来获取区域的大小。
如果您不知道绘制区域的大小(例如,如果 Brush
分配给 Text),您可以扩展 Shader
并在 createShader
函数中利用绘制区域的大小。
在此示例中,将大小除以 4,以重复图案 4 次
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) )

您还可以更改任何其他渐变(例如径向渐变)的画笔大小。如果您未指定大小和中心,则渐变将占据 DrawScope
的完整边界,并且径向渐变的中心默认为 DrawScope
边界的中心。这导致径向渐变的中心显示为较小维度(宽度或高度)的中心
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )

当径向渐变更改为将半径大小设置为最大维度时,您可以看到它产生了更好的径向渐变效果
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) )

值得注意的是,传递到着色器创建的实际大小是根据其调用位置确定的。默认情况下,如果大小与上次创建 Brush
的大小不同,或者如果用于创建着色器的状态对象已更改,Brush
将在内部重新分配其 Shader
。
以下代码随着绘制区域大小的变化,以不同大小创建着色器三次
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) } } } )
使用图片作为画笔
要使用 ImageBitmap 作为 Brush
,请将图片加载为 ImageBitmap
,然后创建 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))
该画笔应用于几种不同类型的绘制:背景、文本和 Canvas。输出如下

请注意,文本现在也使用 ImageBitmap
进行渲染,以绘制文本的像素。
高级示例:自定义画笔
AGSL RuntimeShader
画笔
AGSL 提供 GLSL 着色器功能的一个子集。着色器可以用 AGSL 编写,并与 Compose 中的画笔一起使用。
要创建着色器画笔,首先将着色器定义为 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()
上述着色器接受两种输入颜色,计算与绘制区域左下角 (vec2(0, 1)
) 的距离,并根据距离在这两种颜色之间进行 mix
。这会产生渐变效果。
然后,创建着色器画笔,并为 resolution
(绘制区域的大小)以及要用作自定义渐变输入的 color
和 color2
设置 uniforms
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) ) }
运行此代码,您可以在屏幕上看到以下渲染内容

值得注意的是,着色器不仅可以实现渐变效果,还可以实现更多功能,因为它们都基于数学计算。有关 AGSL 的更多信息,请查阅 AGSL 文档。
其他资源
有关在 Compose 中使用 Brush 的更多示例,请查看以下资源
- 在 Compose 中为画笔文本着色添加动画效果 🖌️
- Compose 中的自定义图形和布局 - Android Dev Summit 2022
- JetLagged 示例 - RuntimeShader 画笔
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本
- 图形修饰符
- Compose 中的图形
- 样式文本