一、Brush 概述
1.1 什么是 Brush
Brush 是 Jetpack Compose 中用于绘制渐变和纹理的抽象类,它可以应用于文字、形状、边框等各种绘制场景。
1.2 继承关系
kotlin
abstract class Brush {
abstract fun applyTo(paint: Paint, size: Size)
}
// 主要子类:
// 1. SolidColor - 纯色
// 2. LinearGradient - 线性渐变
// 3. RadialGradient - 径向渐变
// 4. SweepGradient - 扫描渐变
// 5. ShaderBrush - 自定义着色器
二、核心 API 详解
2.1 SolidColor - 纯色画笔
kotlin
// 基本用法
Brush.solid(Color.Red)
// 等价于
Color.Red.asBrush()
// 内部实现
class SolidColor(val value: Color) : Brush() {
override fun applyTo(paint: Paint, size: Size) {
paint.color = value
paint.shader = null
}
}
2.2 LinearGradient - 线性渐变
构造参数详解
kotlin
Brush.linearGradient(
// 必需参数:颜色列表
colors: List<Color>,
// 可选参数:颜色停止点(0.0-1.0)
stops: List<Float>? = null,
// 渐变起始点(相对坐标,0-1或具体像素值)
start: Offset = Offset.Zero,
// 渐变结束点
end: Offset = Offset.Infinite,
// 渐变平铺模式
tileMode: TileMode = TileMode.Clamp
)
示例详解
kotlin
// 1. 基础水平渐变
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue)
// 默认:start = Offset(0f, 0f), end = Offset(Float.POSITIVE_INFINITY, 0f)
)
// 2. 对角线渐变
Brush.linearGradient(
colors = listOf(Color.Red, Color.Green, Color.Blue),
start = Offset(0f, 0f), // 左上角
end = Offset(100f, 100f) // 右下角(像素值)
)
// 3. 带停止点的精确控制
Brush.linearGradient(
colors = listOf(
Color.Red, // 0%
Color.Yellow, // 30%
Color.Green // 100%
),
stops = listOf(0f, 0.3f, 1f)
)
// 4. 使用相对坐标(0-1范围)
Brush.linearGradient(
0.0f to Color.Red,
0.5f to Color.White,
1.0f to Color.Blue,
start = Offset(0f, 0.5f), // 左中
end = Offset(1f, 0.5f) // 右中
)
2.3 RadialGradient - 径向渐变
构造参数
kotlin
Brush.radialGradient(
colors: List<Color>,
center: Offset = Offset.Unspecified,
radius: Float = Float.POSITIVE_INFINITY,
stops: List<Float>? = null,
tileMode: TileMode = TileMode.Clamp
)
示例详解
kotlin
// 1. 从中心向外扩散
Brush.radialGradient(
colors = listOf(Color.Red, Color.Transparent),
center = Offset(50f, 50f), // 中心点坐标
radius = 50f // 渐变半径
)
// 2. 使用相对坐标
Canvas(modifier = Modifier.size(200.dp)) {
drawCircle(
brush = Brush.radialGradient(
colors = listOf(Color.Yellow, Color.Red),
center = center, // 画布中心
radius = size.minDimension / 2 // 半径 = 宽高最小值的一半
)
)
}
// 3. 多色径向渐变
Brush.radialGradient(
0.0f to Color.White,
0.3f to Color.Yellow,
0.6f to Color.Orange,
1.0f to Color.Red,
center = Offset(100f, 100f),
radius = 150f
)
2.4 SweepGradient - 扫描渐变(扇形渐变)
构造参数
kotlin
Brush.sweepGradient(
colors: List<Color>,
center: Offset = Offset.Unspecified,
stops: List<Float>? = null,
tileMode: TileMode = TileMode.Clamp
)
示例详解
kotlin
// 1. 基础扫描渐变
Brush.sweepGradient(
colors = listOf(
Color.Red,
Color.Yellow,
Color.Green,
Color.Blue,
Color.Red // 闭合循环
),
center = Offset(100f, 100f)
)
// 2. 彩虹效果
val rainbowColors = listOf(
Color.Red,
Color(0xFFFF7F00), // 橙色
Color.Yellow,
Color.Green,
Color.Blue,
Color(0xFF4B0082), // 靛蓝
Color(0xFF9400D3), // 紫色
Color.Red
)
Brush.sweepGradient(
colors = rainbowColors,
center = center
)
2.5 ShaderBrush - 自定义着色器
高级用法
kotlin
// 1. 使用 Android 原生 Shader
val customBrush = remember {
ShaderBrush(
LinearGradient(
floatArrayOf(0f, 0f, 100f, 100f),
intArrayOf(Color.Red.toArgb(), Color.Blue.toArgb()),
null,
Shader.TileMode.CLAMP
)
)
}
// 2. 创建 Perlin 噪声纹理
val noiseBrush = remember {
ShaderBrush(
RuntimeShader("""
uniform float2 size;
uniform float time;
half4 main(float2 fragCoord) {
float2 uv = fragCoord / size;
float noise = fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453);
return half4(noise, noise, noise, 1.0);
}
""".trimIndent()).apply {
setFloatUniform("size", 200f, 200f)
}
)
}
三、TileMode 详解
3.1 三种平铺模式
kotlin
enum class TileMode {
// 1. Clamp - 边缘颜色延伸
Clamp,
// 2. Repeated - 重复平铺
Repeated,
// 3. Mirror - 镜像平铺
Mirror,
// 4. Decal - 边缘透明(API 31+)
Decal
}
3.2 示例对比
kotlin
// Clamp 模式
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue),
start = Offset(0f, 0f),
end = Offset(50f, 0f), // 渐变区域只有50像素
tileMode = TileMode.Clamp // 50像素后保持蓝色
)
// Repeated 模式
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue),
start = Offset(0f, 0f),
end = Offset(50f, 0f),
tileMode = TileMode.Repeated // 每50像素重复一次
)
// Mirror 模式
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue),
start = Offset(0f, 0f),
end = Offset(50f, 0f),
tileMode = TileMode.Mirror // 红->蓝->红->蓝 镜像
)
四、性能优化技巧
4.1 Brush 的重用
kotlin
// ❌ 错误:每次重组都创建新的 Brush
@Composable
fun MyComponent() {
Box(
modifier = Modifier
.background(
Brush.linearGradient(colors = listOf(Color.Red, Color.Blue)) // 每次都新建
)
)
}
// ✅ 正确:使用 remember 缓存
@Composable
fun MyComponent() {
val gradientBrush = remember {
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue),
start = Offset.Zero,
end = Offset.Infinite
)
}
Box(modifier = Modifier.background(gradientBrush))
}
// ✅ 进阶:根据状态变化缓存
val gradientBrush = remember(key1 = colors, key2 = direction) {
Brush.linearGradient(
colors = colors,
start = when(direction) {
Direction.Horizontal -> Offset.Zero
Direction.Vertical -> Offset(0f, 0f)
},
end = when(direction) {
Direction.Horizontal -> Offset.Infinite
Direction.Vertical -> Offset(0f, Float.POSITIVE_INFINITY)
}
)
}
4.2 使用 drawWithCache
kotlin
Canvas(
modifier = Modifier
.size(200.dp)
.drawWithCache {
val brush = Brush.radialGradient(
colors = listOf(Color.Red, Color.Transparent),
center = center,
radius = size.minDimension / 2
)
onDrawBehind {
drawCircle(brush)
}
}
)
五、高级应用示例
5.1 动态动画渐变
kotlin
@Composable
fun AnimatedGradient() {
var progress by remember { mutableFloatStateOf(0f) }
LaunchedEffect(Unit) {
while (true) {
progress = (progress + 0.01f) % 1f
delay(16) // ~60fps
}
}
val animatedBrush by animateBrushAsState(
targetValue = Brush.sweepGradient(
colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue),
center = Offset(100f, 100f)
),
animationSpec = tween(1000)
)
Canvas(modifier = Modifier.size(200.dp)) {
rotate(progress * 360) {
drawCircle(brush = animatedBrush)
}
}
}
5.2 渐变蒙版效果
kotlin
@Composable
fun GradientMask() {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
Image(
painter = painterResource(id = R.drawable.landscape),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.matchParentSize()
)
// 顶部到中部的渐变蒙版
Box(
modifier = Modifier
.matchParentSize()
.background(
brush = Brush.verticalGradient(
0.0f to Color.Black.copy(alpha = 0.8f),
0.3f to Color.Black.copy(alpha = 0.3f),
0.7f to Color.Transparent,
1.0f to Color.Black.copy(alpha = 0.5f)
)
)
)
}
}
5.3 自定义渐变形状
kotlin
@Composable
fun CustomGradientShape() {
Canvas(modifier = Modifier.size(300.dp)) {
// 创建复杂路径
val path = Path().apply {
moveTo(size.width * 0.5f, 0f)
lineTo(size.width, size.height * 0.3f)
lineTo(size.width * 0.8f, size.height)
lineTo(size.width * 0.2f, size.height)
lineTo(0f, size.height * 0.3f)
close()
}
// 应用渐变
drawPath(
path = path,
brush = Brush.linearGradient(
colors = listOf(
Color(0xFF667EEA),
Color(0xFF764BA2),
Color(0xFF6B8DD6),
Color(0xFF8E37D7)
),
start = Offset(0f, 0f),
end = Offset(size.width, size.height)
)
)
}
}
六、常见问题与解决方案
6.1 Brush 不显示或显示异常
kotlin
// 问题:Brush 在 small 尺寸下不显示
// 原因:end 使用 Offset.Infinite 但尺寸太小
// 解决方案:使用具体值或相对值
Box(
modifier = Modifier
.size(50.dp)
.background(
Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue),
// end = Offset.Infinite, // ❌ 可能不显示
end = Offset(50f, 0f) // ✅ 使用具体值
)
)
)
6.2 性能问题排查
kotlin
// 使用 CompositionLocalProvider 调试
CompositionLocalProvider(
LocalDensity provides Density(1f) // 强制 1:1 密度
) {
// 测试 Brush 渲染
}
6.3 内存优化
kotlin
// 对于静态渐变,使用 const val
private val STATIC_GRADIENT = Brush.linearGradient(
colors = listOf(Color.Red, Color.Blue)
)
@Composable
fun StaticComponent() {
Box(modifier = Modifier.background(STATIC_GRADIENT))
}
七、最佳实践总结
- 选择合适的渐变类型:简单渐变用 Linear,圆形用 Radial,环形用 Sweep
- 合理使用坐标系统:理解绝对坐标与相对坐标的区别
- 缓存 Brush 对象:使用 remember 避免不必要的重建
- 注意性能影响:复杂的 Brush 会影响渲染性能
- 测试不同配置:在不同屏幕密度和尺寸下测试效果
- 利用动画 API:使用 animateBrushAsState 实现平滑过渡
通过深入理解 Brush API 的各个参数和特性,可以创建出丰富、高效的渐变效果,提升应用的视觉体验。