使用修饰符和 DrawScope
的基本绘制
在 Compose 中绘制自定义内容的核心方法是使用修饰符,例如 [Modifier.drawWithContent
]、[Modifier.drawBehind
] 和 [Modifier.drawWithCache
]。
例如,如需在可组合项后面绘制内容,您可以使用 drawBehind
修饰符开始执行绘制命令:
Spacer(
modifier = Modifier
.fillMaxSize()
.drawBehind {
// this = DrawScope
}
)
所有绘制修饰符都会提供 [DrawScope
](一个维护自身状态且限定了作用域的绘制环境),可供您为一组图形元素设置参数。DrawScope
提供了几个有用的字段,例如 size
(用于指定 DrawScope
的当前尺寸的 Size
对象)。
如需绘制内容,您可以使用 DrawScope
上的众多绘制函数之一。例如,以下代码会在屏幕的左上角绘制一个矩形:

Canvas(modifier = Modifier.fillMaxSize()) {
val canvasQuadrantSize = size / 2F
drawRect(
color = Color.Magenta,
size = canvasQuadrantSize
)
}
坐标系
如需在屏幕上绘制内容,您需要知道相应项目的偏移量(x
和 y
)和大小。对于 DrawScope
上的许多绘制方法,位置和尺寸由[默认参数值]提供。默认参数通常会将项目放置在画布的 [0, 0]
点上,并提供填充整个绘制区域的默认 size
,如上例所示,您可以看到矩形被放置在左上角。若要调整项目的尺寸和位置,您需要了解 Compose 中的坐标系。
坐标系的原点 ([0,0]
) 位于绘制区域最左上角的像素处。x
会随着向右移动而增加,y
则会随着向下移动而增加。
例如,如果想要绘制一条从画布区域右上角到左下角的对角线,您可以使用 [DrawScope.drawLine()
] 函数,并指定具有对应 x 和 y 位置的起始和结束偏移量:

Canvas(modifier = Modifier.fillMaxSize()) {
val canvasWidth = size.width
val canvasHeight = size.height
drawLine(
start = Offset(x = canvasWidth, y = 0f),
end = Offset(x = 0f, y = canvasHeight),
color = Color.Blue
)
}
基本转换
DrawScope
会提供一些用于更改绘制命令执行位置或方式的转换。
缩放
[DrawScope.scale()
]可用于按系数来增加绘制操作的大小。scale()
之类的操作适用于相应 lambda 中的所有绘图操作。例如,以下代码会将 scaleX
的大小增加 10 倍,并将 scaleY
的大小增加 15 倍:

Canvas(modifier = Modifier.fillMaxSize()) {
scale(scaleX = 10f, scaleY = 15f) {
drawCircle(Color.Blue, radius = 20.dp.toPx())
}
}
平移
[DrawScope.translate()
] 可用于向上、向下、向左或向右移动绘制操作。例如,以下代码会将绘制操作向右移动 100 像素,同时向上移动 300 像素:

Canvas(modifier = Modifier.fillMaxSize()) {
translate(left = 100f, top = -300f) {
drawCircle(Color.Blue, radius = 200.dp.toPx())
}
}
旋转
[DrawScope.rotate()
] 可用于围绕某个轴心点旋转绘制操作。例如,以下代码会将矩形旋转 45 度:

Canvas(modifier = Modifier.fillMaxSize()) {
rotate(degrees = 45F) {
drawRect(
color = Color.Gray,
topLeft = Offset(x = size.width / 3F, y = size.height / 3F),
size = size / 3F
)
}
}
常用绘制操作
绘制文本
如需在 Compose 中绘制文本,您一般可以使用 Text
可组合项。不过,如果您使用的是 DrawScope
,或想通过自定义设置手动绘制文本,则可以使用 [DrawScope.drawText()
] 方法。
如需绘制文本,请使用 [rememberTextMeasurer
] 创建 [TextMeasurer
],然后使用 Measurer 调用 drawText
:
val textMeasurer = rememberTextMeasurer()
Canvas(modifier = Modifier.fillMaxSize()) {
drawText(textMeasurer, "Hello")
}

测量文本
绘制文本的方式与其他绘制命令略有不同。通常情况下,您会在绘制命令中指定绘制形状/图片所需的尺寸(宽度和高度)。在绘制文本时,您可以通过几个参数来控制所呈现文本的大小,例如字体大小、字体、连字和字母间距。
在 Compose 中,您可以使用 [TextMeasurer
] 来获取根据上述因素测量的文本大小。如果您想在文本后面绘制背景,可以通过测量的信息获知文本所占区域的大小:
val textMeasurer = rememberTextMeasurer()
Spacer(
modifier = Modifier
.drawWithCache {
val measuredText =
textMeasurer.measure(
AnnotatedString(longTextSample),
constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()),
style = TextStyle(fontSize = 18.sp)
)
onDrawBehind {
drawRect(pinkColor, size = measuredText.size.toSize())
drawText(measuredText)
}
}
.fillMaxSize()
)
上述代码段会在文本上生成粉色背景:

如果调整约束条件、字体大小或任何会影响测量尺寸的属性,系统就会报告新的尺寸。您可以为 width
和 height
设置固定大小,然后文本会遵循设定的 [TextOverflow
]。例如,以下代码会在可组合项区域的 1⁄3 高度和 1⁄3 宽度内呈现文本,并将 TextOverflow
设置为 TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer()
Spacer(
modifier = Modifier
.drawWithCache {
val measuredText =
textMeasurer.measure(
AnnotatedString(longTextSample),
constraints = Constraints.fixed(
width = (size.width / 3f).toInt(),
height = (size.height / 3f).toInt()
),
overflow = TextOverflow.Ellipsis,
style = TextStyle(fontSize = 18.sp)
)
onDrawBehind {
drawRect(pinkColor, size = measuredText.size.toSize())
drawText(measuredText)
}
}
.fillMaxSize()
)
文本现在按照约束条件绘制,末尾带有省略号:

绘制图片
如需使用 DrawScope
绘制 [ImageBitmap
],请使用 ImageBitmap.imageResource()
加载图片,然后调用 drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
drawImage(dogImage)
})

绘制基本形状
DrawScope
上有许多形状绘制函数。如需绘制形状,请使用其中一个预定义的绘制函数,例如 drawCircle
:
val purpleColor = Color(0xFFBA68C8)
Canvas(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
onDraw = {
drawCircle(purpleColor)
}
)
CanvasSnippets.kt
API | 输出 |
---|---|
drawCircle() | ![]() |
drawRect() | ![]() |
drawRoundedRect() | ![]() |
drawLine() | ![]() |
drawOval() | ![]() |
drawArc() | ![]() |
drawPoints() | ![]() |