如何使用TextPainter在Canvas上绘制带描边的文字?
Canvas TextPainter 实现文字描边效果方案
实现逻辑和你当前用Stack堆叠两个Text组件的思路完全一致,只要在Canvas绘制时先绘制描边文本、再绘制填充文本即可,修改代码如下:
第一步:修改TextData扩展方法
新增生成描边文本TextPainter的方法,和Widget层的描边样式参数保持完全一致:
extension TextDataToTextPainter on TextData { // 原有生成填充文本TextPainter的方法保留,修改方法名方便区分 TextPainter composeFillText() { return TextPainter( textAlign: textAlignment, textDirection: textDirection, maxLines: maxLines, textScaleFactor: textScaleFactor, text: TextSpan( text: text, style: getTextStyle(), ), ); } // 新增生成描边文本TextPainter的方法 TextPainter composeStrokeText() { final baseStyle = getTextStyle(); return TextPainter( textAlign: textAlignment, textDirection: textDirection, maxLines: maxLines, textScaleFactor: textScaleFactor, text: TextSpan( text: text, style: baseStyle.copyWith( foreground: Paint() ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round ..strokeJoin = StrokeJoin.round ..strokeWidth = textStrokeSize ..color = textStrokeSize == 0 ? Colors.transparent : textStrokeColor, color: null, ), ), ); } }
第二步:修改EditorTextPainter绘制逻辑
调整draw方法,先绘制描边层,再绘制填充层:
class EditorTextPainter extends ElementPainter<TransformData<TextData>> { @override Future<void> draw(Canvas canvas, Size size, TransformData<TextData> data) { canvas.saveLayer(Offset.zero & size, Paint()); final textData = data.data; final offset = data.offset.alongSize(size); final textSize = data.size.toActualSize(size); // 先绘制描边层 final strokeText = textData.composeStrokeText(); strokeText.layout(maxWidth: textSize.width); strokeText.paint(canvas, offset); // 再绘制填充层,覆盖在描边上方 final fillText = textData.composeFillText(); fillText.layout(maxWidth: textSize.width); fillText.paint(canvas, offset); canvas.rotate(data.angle); canvas.restore(); return Future.value(); } }
注意事项
- 绘制顺序不能颠倒,必须先画描边再画填充,否则描边会覆盖在文字上方
- 如遇到描边宽度过大导致的偏移问题,可以微调填充文本的绘制偏移对齐
- 无需修改其他逻辑,最终渲染效果和Widget层堆叠Text的效果完全一致
内容的提问来源于stack exchange,提问作者Ali Qanbari
相关产品推荐
相关产品推荐

