You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose Canvas中drawText与圆形的颜色混合实现

解决Jetpack Compose圆形上方文本变白的简便方法

方法一:固定位置文本直接指定颜色

如果文本位置固定(比如示例中的B完全落在圆形区域内),最直接的方式就是给圆形上的文本单独设置白色,其他区域文本保持黑色:

Canvas(
    modifier = Modifier.size(256.dp),
    onDraw = {
        val center = Offset(size.width / 2, size.height / 2)
        val textSize = textMeasurer.measure(text = AnnotatedString("A"))
        
        drawCircle(
            color = Color.Magenta,
            radius = 50f,
            center = center
        )
        
        // 圆形外的文本用黑色
        drawText(
            textMeasurer = textMeasurer,
            text = "A",
            style = TextStyle(
                color = Color.Black,
                fontSize = 14.sp
            ),
            topLeft = Offset(
                x = center.x - 100f - (textSize.size.width / 2),
                y = center.y - (textSize.size.height / 2)
            )
        )
        
        // 圆形上的文本直接用白色
        drawText(
            textMeasurer = textMeasurer,
            text = "B",
            style = TextStyle(
                color = Color.White,
                fontSize = 14.sp
            ),
            topLeft = Offset(
                x = center.x - (textSize.size.width / 2),
                y = center.y - (textSize.size.height / 2)
            )
        )
    }
)

方法二:动态判断文本位置(通用方案)

如果文本位置是动态的,不确定是否落在圆形内,可以通过计算文本中心到圆形中心的距离,动态切换文本颜色:

Canvas(
    modifier = Modifier.size(256.dp),
    onDraw = {
        val center = Offset(size.width / 2, size.height / 2)
        val radius = 50f
        val textSize = textMeasurer.measure(text = AnnotatedString("A"))
        
        drawCircle(
            color = Color.Magenta,
            radius = radius,
            center = center
        )
        
        // 处理文本A:判断是否在圆形内
        val aTopLeft = Offset(
            x = center.x - 100f - (textSize.size.width / 2),
            y = center.y - (textSize.size.height / 2)
        )
        val aCenter = Offset(
            x = aTopLeft.x + textSize.size.width / 2,
            y = aTopLeft.y + textSize.size.height / 2
        )
        val aDistance = sqrt((aCenter.x - center.x).pow(2) + (aCenter.y - center.y).pow(2))
        drawText(
            textMeasurer = textMeasurer,
            text = "A",
            style = TextStyle(
                color = if (aDistance <= radius) Color.White else Color.Black,
                fontSize = 14.sp
            ),
            topLeft = aTopLeft
        )
        
        // 处理文本B:判断是否在圆形内
        val bTopLeft = Offset(
            x = center.x - (textSize.size.width / 2),
            y = center.y - (textSize.size.height / 2)
        )
        val bCenter = Offset(
            x = bTopLeft.x + textSize.size.width / 2,
            y = bTopLeft.y + textSize.size.height / 2
        )
        val bDistance = sqrt((bCenter.x - center.x).pow(2) + (bCenter.y - center.y).pow(2))
        drawText(
            textMeasurer = textMeasurer,
            text = "B",
            style = TextStyle(
                color = if (bDistance <= radius) Color.White else Color.Black,
                fontSize = 14.sp
            ),
            topLeft = bTopLeft
        )
    }
)

方法三:裁剪图层覆盖(复杂场景适配)

如果需要批量处理多个文本,或文本形状不规则,可以用withClipPath裁剪出圆形区域,在区域内绘制白色文本覆盖黑色:

Canvas(
    modifier = Modifier.size(256.dp),
    onDraw = {
        val center = Offset(size.width / 2, size.height / 2)
        val radius = 50f
        val textSize = textMeasurer.measure(text = AnnotatedString("A"))
        
        // 绘制圆形背景
        drawCircle(
            color = Color.Magenta,
            radius = radius,
            center = center
        )
        
        // 绘制所有黑色文本
        drawText(
            textMeasurer = textMeasurer,
            text = "A",
            style = TextStyle(color = Color.Black, fontSize = 14.sp),
            topLeft = Offset(
                x = center.x - 100f - (textSize.size.width / 2),
                y = center.y - (textSize.size.height / 2)
            )
        )
        val bTopLeft = Offset(
            x = center.x - (textSize.size.width / 2),
            y = center.y - (textSize.size.height / 2)
        )
        drawText(
            textMeasurer = textMeasurer,
            text = "B",
            style = TextStyle(color = Color.Black, fontSize = 14.sp),
            topLeft = bTopLeft
        )
        
        // 裁剪圆形区域,绘制白色文本覆盖原有黑色
        withClipPath(Path().apply { addOval(Rect(center.x - radius, center.y - radius, center.x + radius, center.y + radius)) }) {
            drawText(
                textMeasurer = textMeasurer,
                text = "B",
                style = TextStyle(color = Color.White, fontSize = 14.sp),
                topLeft = bTopLeft
            )
        }
    }
)

内容的提问来源于stack exchange,提问作者AndreasLill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 07:05:21