How to draw custom stroke for text in Jetpack Compose?
1. 简介
从 Jetpack Compose 的 compose-ui 库 1.4.0-alpha01 版本开始为 TextStyle
, SpanStyle
, Paragraph
, MultiParagraph
, 等增加了 DrawStyle
属性用于绘制文字笔画/轮廓效果。
更多关于 DrawStyle 的介绍可以查看另一篇文章:Jetpack Compose 中 DrawStyle 详解
2. 自定义笔画
Compose 中定义了两个 DrawStyle 的子类:Fill
和 Stroke
Fill
是 drawStyle
属性的默认值,表示应使用所提供的颜色或图案完全填充形状。
Stroke
是为带有笔画的绘制提供信息。
2.1 默认效果:Fill
Text(
text = "https://itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 32.sp,
drawStyle = Fill,
),
),
)
Fill
是 drawStyle
属性的默认值,表示应使用所提供的颜色或图案完全填充形状。
2.2 使用 Stroke 实现自定义效果
2.2.1 简单的描边效果
使用 Stroke 类型的 drawStyle 属性可以自定义文字的绘制样式,如指定笔画的宽度和笔画间的连接方式,可以实现简单的描边效果:
笔画的连接方式有三种:Miter
尖角/斜接, Round
圆角, Bevel
平角
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(width = 16f, join = StrokeJoin.Miter),
),
),
)
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(width = 16f, join = StrokeJoin.Round),
),
),
)
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(width = 16f, join = StrokeJoin.Bevel),
),
),
)
本文中使用的是可组合项 Text
来绘制文字,我们也可以使用 drawText
方法在 DrawScope
中绘制,它们的用法相同,都是通过 drawType
属性来实现
Canvas(Modifier.fillMaxWidth().height(100.dp)) {
drawText(
textMeasurer = textMeasurer,
text = "https://itmob.cn",
style = TextStyle(
fontSize = 36.sp,
drawStyle = Stroke(
width = 2.dp.toPx(),
drawStyle = Stroke(width = 16f, join = StrokeJoin.Round),
),
),
)
}
2.2.2 更复杂的描边效果
通过 PathEffect
实现更复杂的描边效果,通过 Path 类型的图形来绘制笔画。
源码中定义了四个方法来创建 PathEffect
对象。分别是:
- cornerPathEffect:将线段之间连接的锐角替换为指定半径的圆角
- dashPathEffect:将笔画绘制为具有给定间隔的一系列短划线/虚线
- stampedPathEffect:通过在绘制的笔画路径上盖指定的形状
- chainPathEffect:PathEffect 组合
关于 PathEffect 的更多介绍参见:pathEffect: PathEffect 应用于笔划的效果
那我们来看看通过 PathEffect 能实现怎样的笔画效果:
-
圆角描边的文本
val radius = with(LocalDensity.current) { 16.dp.toPx() }
val strokeWidth = with(LocalDensity.current) { 2.dp.toPx() }
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(
width = strokeWidth,
pathEffect = PathEffect.cornerPathEffect(radius),
),
),
),
)
-
虚线描边的文本
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(
width = strokeWidth,
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(10F, 10F),
phase = 0F,
),
),
),
),
)
-
使用 Path 类型的图形来描边的文本
// 使用 Path 创建三角形图形,用三角形绘制文本笔画
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(
width = strokeWidth,
pathEffect = PathEffect.stampedPathEffect(
shape = Path().apply {
val size = 5F
moveTo(size / 2, 0F)
lineTo(0F, size)
lineTo(size, size)
lineTo(size / 2, 0F)
close()
},
advance = 10F,
phase = 0F,
style = StampedPathEffectStyle.Morph,
),
),
),
),
)
-
多个路径效果合并来描边的文本
// 笔画使用圆角连接,并且显示为虚线
val radius = with(LocalDensity.current) { 16.dp.toPx() }
Text(
text = "itmob.cn",
style = LocalTextStyle.current.merge(
TextStyle(
color = Color.Red,
fontSize = 86.sp,
drawStyle = Stroke(
width = strokeWidth,
pathEffect = PathEffect.chainPathEffect(
outer = PathEffect.dashPathEffect(
intervals = floatArrayOf(10F, 10F),
phase = 0F,
),
inner = PathEffect.cornerPathEffect(radius),
),
),
),
),
)
3. 总结
通过这个 DrawStyle
属性可以在 drawText 和 Text 等文本控件中实现自定义的文字描边/轮廓样式。
其他
更多关于 Jetpack Compose 文本的介绍:
在 Jetpack Compose 中怎样实现印章样式(弧形)的文字效果?
Jetpack Compose 中 DrawStyle 详解 - (线段/笔画/轮廓的绘制样式)
Jetpack Compose 中怎样隐藏或禁用 TextField(文本字段)的光标、文本选择手柄和文本工具栏?
怎样处理 Jetpack Compose 中文本的长按选择和点击事件(如何在 Text 中添加超链接?)
Jetpack Compose TextField VisualTransformation 视觉转换详解-高亮显示URL-格式化显示银行卡号码
怎样处理 Jetpack Compose 中文本的长按选择和点击事件(如何在 Text 中添加超链接?)
Jetpack Compose 怎样实现跑马灯效果(Marquee)
在 Jetpack Compose 中使用 DrawScope.drawText API 将文本绘制到 Canvas 上