Jetpack Compose Brush 渐变

12 阅读11分钟

Jetpack Compose Brush 渐变

目录

  1. Brush类基础概念
  2. 渐变类型详解
  3. UI组件应用方法
  4. 代码示例
  5. 性能优化与最佳实践
  6. 与传统View系统对比

一、Brush类基础概念

1.1 什么是Brush

在Jetpack Compose中,Brush是一个抽象类,用于定义**着色器(Shader)**的创建方式。它是Compose图形系统的核心组件之一,负责描述如何将颜色应用到绘制区域。

// Brush位于androidx.compose.ui.graphics包中
abstract class Brush {
    abstract fun applyTo(size: Size, paint: Paint, alpha: Float = 1.0f)
    
    // 创建着色器的内部方法
    internal abstract fun createShader(size: Size): Shader
}

1.2 Brush在Compose中的定位

Compose图形渲染层级:
┌─────────────────────────────────────┐
│           UI组件层                   │
│    (Box, Text, Button, Canvas...)   │
├─────────────────────────────────────┤
│           Modifier层                 │
│    (background, border, drawWith...) │
├─────────────────────────────────────┤
│           Brush层                    │
│    (LinearGradient, RadialGradient) │
├─────────────────────────────────────┤
│           Paint/Shader层             │
│    (Android底层图形API)              │
└─────────────────────────────────────┘

1.3 Brush的核心特性

特性说明
延迟计算Brush在绘制时才根据实际尺寸创建Shader
尺寸自适应自动适应目标组件的尺寸变化
可复用性同一个Brush实例可应用于多个组件
动画支持支持配合animate*函数实现动态渐变效果

二、渐变类型详解

2.1 LinearGradient(线性渐变)

线性渐变是最常用的渐变类型,颜色沿一条直线从起点过渡到终点。

2.1.1 基础构造函数
// 方式1:使用Offset指定起点和终点
fun LinearGradient(
    colors: List<Color>,              // 颜色列表(至少2个)
    start: Offset,                    // 渐变起点坐标
    end: Offset,                      // 渐变终点坐标
    tileMode: TileMode = TileMode.Clamp  // 平铺模式
): Brush

// 方式2:使用颜色与位置配对
fun LinearGradient(
    colorStops: List<Pair<Float, Color>>,  // 颜色停止点(位置0.0-1.0, 颜色)
    start: Offset,
    end: Offset,
    tileMode: TileMode = TileMode.Clamp
): Brush
2.1.2 参数详解

坐标系统说明:

(0,0) ─────────────────── (width,0)
   │                         │
   │       组件区域           │
   │                         │
(0,height) ───────── (width,height)

常用渐变方向:

// 水平渐变(左到右)
val horizontalGradient = Brush.linearGradient(
    colors = listOf(Color.Red, Color.Blue),
    start = Offset(0f, 0f),
    end = Offset(Float.POSITIVE_INFINITY, 0f)  // 或使用具体宽度
)

// 垂直渐变(上到下)
val verticalGradient = Brush.linearGradient(
    colors = listOf(Color.Red, Color.Blue),
    start = Offset(0f, 0f),
    end = Offset(0f, Float.POSITIVE_INFINITY)
)

// 对角线渐变
val diagonalGradient = Brush.linearGradient(
    colors = listOf(Color.Red, Color.Blue),
    start = Offset(0f, 0f),
    end = Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
)

TileMode(平铺模式):

模式说明视觉效果
Clamp边缘颜色延伸(默认)边缘颜色无限延伸
Repeated重复渐变图案周期性重复
Mirror镜像重复正反交替重复
Decal透明延伸边缘外透明
2.1.3 颜色分布控制
// 使用colorStops精确控制颜色分布
val preciseGradient = Brush.linearGradient(
    colorStops = listOf(
        0.0f to Color.Red,      // 起点:红色
        0.3f to Color.Yellow,   // 30%位置:黄色
        0.7f to Color.Green,    // 70%位置:绿色
        1.0f to Color.Blue      // 终点:蓝色
    ),
    start = Offset.Zero,
    end = Offset.Infinite
)

2.2 RadialGradient(径向渐变)

径向渐变从中心点向外辐射,颜色从中心向边缘过渡。

2.2.1 构造函数
fun RadialGradient(
    colors: List<Color>,
    center: Offset,                   // 渐变中心点
    radius: Float,                    // 渐变半径
    tileMode: TileMode = TileMode.Clamp
): Brush

// 带颜色停止点的版本
fun RadialGradient(
    colorStops: List<Pair<Float, Color>>,
    center: Offset,
    radius: Float,
    tileMode: TileMode = TileMode.Clamp
): Brush
2.2.2 参数详解与应用
// 基础径向渐变
val basicRadial = Brush.radialGradient(
    colors = listOf(Color.White, Color.Black),
    center = Offset(150f, 150f),  // 中心点坐标
    radius = 200f                 // 半径(像素)
)

// 中心对齐的径向渐变(使用组件尺寸)
val centeredRadial = Brush.radialGradient(
    colors = listOf(
        Color(0xFF667eea),
        Color(0xFF764ba2)
    ),
    center = Offset(0.5f, 0.5f),  // 使用比例定位中心
    radius = 0.5f                 // 使用比例作为半径
)

注意事项:

  1. 半径值超过目标区域时,TileMode决定外部如何填充
  2. 中心点可以使用绝对坐标或相对比例
  3. 适合创建发光、 spotlight、圆形按钮等效果

2.3 SweepGradient(扫描渐变/角度渐变)

扫描渐变围绕中心点按角度旋转分布颜色,类似雷达扫描效果。

2.3.1 构造函数
fun SweepGradient(
    colors: List<Color>,
    center: Offset                    // 旋转中心点
): Brush

// 带颜色停止点
fun SweepGradient(
    colorStops: List<Pair<Float, Color>>,
    center: Offset
): Brush
2.3.2 角度计算原理
        270° (-90°)
            │
            │
   180° ────┼──── 0° (360°)
            │
            │
         90°

颜色分布从0°开始,顺时针方向排列
// 彩虹色扫描渐变
val rainbowSweep = Brush.sweepGradient(
    colorStops = listOf(
        0.0f to Color.Red,      // 0°
        0.17f to Color.Yellow,  // ~60°
        0.33f to Color.Green,   // ~120°
        0.5f to Color.Cyan,     // 180°
        0.67f to Color.Blue,    // ~240°
        0.83f to Color.Magenta, // ~300°
        1.0f to Color.Red       // 360°
    ),
    center = Offset(0.5f, 0.5f)
)
2.3.3 应用场景
  • 圆形进度指示器
  • 色轮/颜色选择器
  • 雷达扫描动画效果
  • 仪表盘刻度背景

2.4 ShaderBrush(自定义着色器Brush)

对于更复杂的渐变需求,可以使用ShaderBrush创建自定义着色器。

// 使用RuntimeShader创建复杂效果(API 33+)
val customShaderBrush = object : ShaderBrush() {
    override fun createShader(size: Size): Shader {
        return RuntimeShader("""
            vec4 main(vec2 coord) {
                float t = coord.x / ${size.width};
                return vec4(t, 0.0, 1.0 - t, 1.0);
            }
        """).apply {
            setFloatUniform("resolution", size.width, size.height)
        }
    }
}

// 使用Compose内置的AgSL着色器
val noiseBrush = ShaderBrush(
    RuntimeShader(NoiseShader).apply {
        setFloatUniform("resolution", 100f, 100f)
    }
)

三、UI组件应用方法

3.1 作为background属性

// 基础用法
Box(
    modifier = Modifier
        .size(200.dp)
        .background(
            brush = Brush.linearGradient(
                colors = listOf(Color.Red, Color.Blue)
            )
        )
)

// 带形状的背景
Box(
    modifier = Modifier
        .size(200.dp)
        .background(
            brush = Brush.radialGradient(
                colors = listOf(Color.Yellow, Color.Transparent)
            ),
            shape = RoundedCornerShape(16.dp)
        )
)

3.2 作为border属性

Box(
    modifier = Modifier
        .size(200.dp)
        .border(
            width = 4.dp,
            brush = Brush.linearGradient(
                colors = listOf(Color.Cyan, Color.Magenta)
            ),
            shape = CircleShape
        )
)

3.3 文本渐变效果

// 方式1:使用brush参数(Compose 1.2.0+)
Text(
    text = "Gradient Text",
    style = TextStyle(
        brush = Brush.linearGradient(
            colors = listOf(Color.Red, Color.Blue)
        ),
        fontSize = 40.sp,
        fontWeight = FontWeight.Bold
    )
)

// 方式2:使用drawWithCache实现更复杂效果
Text(
    text = "Gradient Text",
    modifier = Modifier.drawWithCache {
        val brush = Brush.linearGradient(
            colors = listOf(Color.Red, Color.Blue),
            start = Offset(0f, 0f),
            end = Offset(size.width, size.height)
        )
        onDrawWithContent {
            drawContent()
            drawRect(
                brush = brush,
                blendMode = BlendMode.SrcAtop  // 只应用于文字
            )
        }
    },
    fontSize = 40.sp,
    fontWeight = FontWeight.Bold
)

3.4 与Modifier结合的高级技巧

3.4.1 drawBehind - 在内容后绘制
Box(
    modifier = Modifier
        .fillMaxSize()
        .drawBehind {
            // 绘制网格背景
            val gridBrush = Brush.linearGradient(
                colors = listOf(Color.Gray.copy(alpha = 0.1f), Color.Transparent),
                start = Offset(0f, 0f),
            end = Offset(50f, 50f),
                tileMode = TileMode.Repeated
            )
            drawRect(brush = gridBrush)
        }
)
3.4.2 drawWithContent - 控制绘制层级
Box(
    modifier = Modifier
        .size(200.dp)
        .drawWithContent {
            // 1. 先绘制渐变背景
            drawRect(
                brush = Brush.radialGradient(
                    colors = listOf(Color.Yellow, Color.Orange)
                )
            )
            
            // 2. 绘制内容
            drawContent()
            
            // 3. 绘制渐变遮罩
            drawRect(
                brush = Brush.verticalGradient(
                    colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.3f))
                ),
                blendMode = BlendMode.Multiply
            )
        }
)

3.5 在Canvas中的高级应用

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasWidth = size.width
    val canvasHeight = size.height
    
    // 1. 绘制渐变矩形
    drawRect(
        brush = Brush.linearGradient(
            colors = listOf(Color.Red, Color.Blue),
            start = Offset(0f, 0f),
            end = Offset(canvasWidth, canvasHeight)
        ),
        size = Size(canvasWidth, canvasHeight)
    )
    
    // 2. 绘制渐变圆形
    drawCircle(
        brush = Brush.radialGradient(
            colors = listOf(Color.White, Color.Transparent),
            center = Offset(canvasWidth / 2, canvasHeight / 2),
            radius = 200f
        ),
        radius = 200f,
        center = Offset(canvasWidth / 2, canvasHeight / 2)
    )
    
    // 3. 绘制渐变路径
    val path = Path().apply {
        moveTo(0f, canvasHeight)
        quadraticBezierTo(
            canvasWidth / 2, canvasHeight - 200f,
            canvasWidth, canvasHeight
        )
        lineTo(canvasWidth, canvasHeight + 200f)
        lineTo(0f, canvasHeight + 200f)
        close()
    }
    
    drawPath(
        path = path,
        brush = Brush.verticalGradient(
            colors = listOf(Color.Cyan, Color.Blue)
        )
    )
}

四、代码示例

示例1:渐变卡片组件(基础应用)

@Composable
fun GradientCardDemo() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        // 线性渐变卡片
        GradientCard(
            title = "Linear Gradient",
            description = "Beautiful linear gradient background",
            brush = Brush.linearGradient(
                colors = listOf(
                    Color(0xFF667eea),
                    Color(0xFF764ba2)
                ),
                start = Offset(0f, 0f),
                end = Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
            )
        )
        
        // 径向渐变卡片
        GradientCard(
            title = "Radial Gradient",
            description = "Elegant radial gradient effect",
            brush = Brush.radialGradient(
                colors = listOf(
                    Color(0xFFf093fb),
                    Color(0xFFf5576c)
                ),
                center = Offset(0.3f, 0.3f),
                radius = 0.8f
            )
        )
        
        // 扫描渐变卡片
        GradientCard(
            title = "Sweep Gradient",
            description = "Dynamic sweep gradient pattern",
            brush = Brush.sweepGradient(
                colorStops = listOf(
                    0.0f to Color(0xFF4facfe),
                    0.5f to Color(0xFF00f2fe),
                    1.0f to Color(0xFF4facfe)
                ),
                center = Offset(0.5f, 0.5f)
            )
        )
    }
}

@Composable
private fun GradientCard(
    title: String,
    description: String,
    brush: Brush
) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(120.dp)
            .background(
                brush = brush,
                shape = RoundedCornerShape(16.dp)
            )
            .padding(20.dp)
    ) {
        Column {
            Text(
                text = title,
                color = Color.White,
                fontSize = 24.sp,
                fontWeight = FontWeight.Bold
            )
            Text(
                text = description,
                color = Color.White.copy(alpha = 0.8f),
                fontSize = 14.sp
            )
        }
    }
}

示例2:渐变文字与边框(高级应用)

@Composable
fun GradientTextAndBorderDemo() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(24.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(32.dp)
    ) {
        // 渐变边框按钮
        GradientBorderButton(
            text = "Gradient Border",
            onClick = { }
        )
        
        // 渐变文字
        GradientText(
            text = "GRADIENT",
            fontSize = 48.sp
        )
        
        // 带渐变遮罩的图片
        GradientImageCard()
    }
}

@Composable
private fun GradientBorderButton(
    text: String,
    onClick: () -> Unit
) {
    val gradientBrush = Brush.linearGradient(
        colors = listOf(
            Color(0xFF00c6ff),
            Color(0xFF0072ff)
        )
    )
    
    Box(
        modifier = Modifier
            .clickable(onClick = onClick)
            .border(
                width = 3.dp,
                brush = gradientBrush,
                shape = RoundedCornerShape(50.dp)
            )
            .padding(horizontal = 32.dp, vertical = 16.dp)
    ) {
        Text(
            text = text,
            color = Color(0xFF0072ff),
            fontSize = 18.sp,
            fontWeight = FontWeight.Medium
        )
    }
}

@Composable
private fun GradientText(
    text: String,
    fontSize: TextUnit
) {
    val gradientBrush = Brush.horizontalGradient(
        colors = listOf(
            Color(0xFFf093fb),
            Color(0xFFf5576c),
            Color(0xFF4facfe),
            Color(0xFF00f2fe)
        )
    )
    
    Text(
        text = text,
        style = TextStyle(
            brush = gradientBrush,
            fontSize = fontSize,
            fontWeight = FontWeight.ExtraBold,
            letterSpacing = 4.sp
        )
    )
}

@Composable
private fun GradientImageCard() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
            .clip(RoundedCornerShape(16.dp))
    ) {
        // 模拟图片
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.DarkGray)
        )
        
        // 底部渐变遮罩
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(
                    brush = Brush.verticalGradient(
                        colors = listOf(
                            Color.Transparent,
                            Color.Transparent,
                            Color.Black.copy(alpha = 0.7f)
                        )
                    )
                )
        )
        
        // 文字内容
        Text(
            text = "Beautiful Gradient Overlay",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier
                .align(Alignment.BottomStart)
                .padding(16.dp)
        )
    }
}

示例3:动态渐变动画(高级场景)

@Composable
fun AnimatedGradientDemo() {
    // 动画状态
    val infiniteTransition = rememberInfiniteTransition(label = "gradient")
    
    // 动画偏移量
    val offset by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(3000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "offset"
    )
    
    // 动画颜色
    val animatedColor by infiniteTransition.animateColor(
        initialValue = Color(0xFF667eea),
        targetValue = Color(0xFF764ba2),
        animationSpec = infiniteRepeatable(
            animation = tween(2000),
            repeatMode = RepeatMode.Reverse
        ),
        label = "color"
    )
    
    Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(24.dp)
    ) {
        // 1. 流动渐变背景
        AnimatedGradientBackground(offset)
        
        // 2. 颜色变化渐变
        ColorShiftingGradient(animatedColor)
        
        // 3. 扫描渐变动画
        RotatingSweepGradient()
        
        // 4. 呼吸效果渐变
        PulsingGradient()
    }
}

@Composable
private fun AnimatedGradientBackground(offset: Float) {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(150.dp)
            .padding(16.dp)
            .background(
                brush = Brush.linearGradient(
                    colors = listOf(
                        Color(0xFFff9a9e),
                        Color(0xFFfecfef),
                        Color(0xFFfecfef),
                        Color(0xFFff9a9e)
                    ),
                    start = Offset(offset * 1000f, 0f),
                    end = Offset(offset * 1000f + 500f, 0f)
                ),
                shape = RoundedCornerShape(16.dp)
            )
    ) {
        Text(
            text = "Flowing Gradient",
            color = Color.White,
            fontSize = 24.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.align(Alignment.Center)
        )
    }
}

@Composable
private fun ColorShiftingGradient(baseColor: Color) {
    Box(
        modifier = Modifier
            .size(150.dp)
            .background(
                brush = Brush.radialGradient(
                    colors = listOf(
                        baseColor,
                        baseColor.copy(red = baseColor.red * 0.7f),
                        Color.DarkGray
                    )
                ),
                shape = CircleShape
            ),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = "Color Shift",
            color = Color.White,
            fontWeight = FontWeight.Bold
        )
    }
}

@Composable
private fun RotatingSweepGradient() {
    val rotation by rememberInfiniteTransition(label = "rotation")
        .animateFloat(
            initialValue = 0f,
            targetValue = 360f,
            animationSpec = infiniteRepeatable(
                animation = tween(4000, easing = LinearEasing)
            ),
            label = "rotation"
        )
    
    Box(
        modifier = Modifier
            .size(150.dp)
            .drawWithCache {
                val brush = Brush.sweepGradient(
                    colorStops = listOf(
                        0.0f to Color.Transparent,
                        0.3f to Color(0xFF00c6ff),
                        0.7f to Color(0xFF0072ff),
                        1.0f to Color.Transparent
                    ),
                    center = Offset(size.width / 2, size.height / 2)
                )
                
                onDrawWithContent {
                    rotate(rotation) {
                        drawCircle(
                            brush = brush,
                            radius = size.minDimension / 2
                        )
                    }
                }
            }
    )
}

@Composable
private fun PulsingGradient() {
    val scale by rememberInfiniteTransition(label = "pulse")
        .animateFloat(
            initialValue = 0.8f,
            targetValue = 1.2f,
            animationSpec = infiniteRepeatable(
                animation = tween(1500),
                repeatMode = RepeatMode.Reverse
            ),
            label = "scale"
        )
    
    Box(
        modifier = Modifier
            .size(150.dp)
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
            }
            .background(
                brush = Brush.radialGradient(
                    colors = listOf(
                        Color(0xFFf093fb).copy(alpha = 0.8f),
                        Color(0xFFf5576c).copy(alpha = 0.4f),
                        Color.Transparent
                    )
                ),
                shape = CircleShape
            )
    )
}

五、性能优化与最佳实践

5.1 性能优化建议

5.1.1 Brush实例复用
// ❌ 错误:每次重组都创建新Brush
@Composable
fun BadExample() {
    Box(
        modifier = Modifier.background(
            brush = Brush.linearGradient(listOf(Color.Red, Color.Blue))  // 每次重组都新建
        )
    )
}

// ✅ 正确:使用remember缓存Brush
@Composable
fun GoodExample() {
    val gradientBrush = remember {
        Brush.linearGradient(listOf(Color.Red, Color.Blue))
    }
    Box(
        modifier = Modifier.background(brush = gradientBrush)
    )
}

// ✅ 更好:使用静态常量
object GradientBrushes {
    val DefaultGradient = Brush.linearGradient(
        listOf(Color(0xFF667eea), Color(0xFF764ba2))
    )
}
5.1.2 避免过度绘制
// ❌ 错误:多层渐变叠加
Box(
    modifier = Modifier
        .background(Brush.linearGradient(...))  // 第一层
        .background(Brush.radialGradient(...))  // 第二层 - 过度绘制
)

// ✅ 正确:合并为单层
Box(
    modifier = Modifier
        .drawWithCache {
            val combinedBrush = // 预计算合并后的效果
            onDrawBehind {
                drawRect(brush = combinedBrush)
            }
        }
)
5.1.3 使用drawWithCache优化复杂绘制
@Composable
fun OptimizedGradientBox() {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .drawWithCache {
                // 在缓存中创建Brush,避免每次重绘都重新计算
                val gradientBrush = Brush.linearGradient(
                    colors = listOf(Color.Red, Color.Blue),
                    start = Offset(0f, 0f),
                    end = Offset(size.width, size.height)
                )
                
                onDrawBehind {
                    drawRect(brush = gradientBrush)
                }
            }
    )
}

5.2 常见问题解决方案

问题原因解决方案
渐变颜色断层色深不足/颜色差异大使用更多过渡色,增加颜色停止点
渐变闪烁Brush频繁重建使用remember缓存Brush实例
尺寸计算错误Offset使用绝对值使用drawWithCache获取实际尺寸
动画卡顿每帧创建Shader使用ShaderBrush配合硬件加速
边缘锯齿TileMode设置不当使用Clamp模式或增大渐变区域

5.3 最佳实践清单

  • 将Brush定义为常量或remember缓存
  • 使用drawWithCache处理复杂渐变效果
  • 避免在动画中频繁创建Brush
  • 合理选择TileMode避免边缘问题
  • 使用colorStops精确控制颜色分布
  • 考虑深色模式下的渐变适配

六、与传统View系统对比

6.1 实现方式对比

特性传统View (XML/Canvas)Jetpack Compose
线性渐变<gradient android:type="linear"/>Brush.linearGradient()
径向渐变<gradient android:type="radial"/>Brush.radialGradient()
扫描渐变<gradient android:type="sweep"/>Brush.sweepGradient()
代码创建LinearGradient ShaderBrush
动态更新需重新创建Drawable/Shader状态驱动自动重组
动画支持需手动处理ValueAnimator直接配合animate*函数

6.2 代码对比示例

传统View方式:

// XML定义
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:type="linear"
        android:angle="45"
        android:startColor="#FF667eea"
        android:endColor="#FF764ba2" />
</shape>

// 代码动态创建
val paint = Paint().apply {
    shader = LinearGradient(
        0f, 0f, width, height,
        Color.parseColor("#FF667eea"),
        Color.parseColor("#FF764ba2"),
        Shader.TileMode.CLAMP
    )
}
canvas.drawRect(rect, paint)

Compose方式:

Box(
    modifier = Modifier
        .fillMaxSize()
        .background(
            brush = Brush.linearGradient(
                colors = listOf(Color(0xFF667eea), Color(0xFF764ba2)),
                start = Offset(0f, 0f),
                end = Offset(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
            )
        )
)

6.3 优劣势分析

Compose Brush优势:

  1. 声明式语法 - 代码更简洁直观
  2. 状态驱动 - 自动响应状态变化重绘
  3. 动画友好 - 无缝集成Compose动画系统
  4. 类型安全 - 编译时检查,减少运行时错误
  5. 可组合性 - 易于封装和复用

传统View优势:

  1. XML预览 - 可在布局编辑器中直观预览
  2. 成熟生态 - 大量现成工具和库支持
  3. 性能调优 - 更底层的控制,特定场景更优

6.4 迁移建议

// 将XML Gradient Drawable迁移到Compose

// 原XML:
// <shape>
//     <gradient android:angle="135" android:startColor="#FF512F" android:endColor="#DD2476"/>
// </shape>

// Compose等效:
val migratedBrush = Brush.linearGradient(
    colors = listOf(Color(0xFF512F), Color(0xFFDD2476)),
    start = Offset(0f, Float.POSITIVE_INFINITY),  // 135度 ≈ 从左下到右上
    end = Offset(Float.POSITIVE_INFINITY, 0f)
)

总结

Jetpack Compose的Brush系统为渐变效果提供了强大而灵活的解决方案。通过理解其底层原理和最佳实践,开发者可以:

  1. 高效创建各类渐变效果(线性、径向、扫描)
  2. 灵活应用于各种UI组件和自定义绘制场景
  3. 流畅实现复杂的渐变动画效果
  4. 优化性能避免常见陷阱

掌握Brush的使用是成为高级Compose开发者的必备技能,希望本指南能帮助您在实际项目中更好地运用渐变效果,打造出色的用户界面。


参考资源