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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 14:54:03