likes
comments
collection
share

flutter 文字绘制与相对位置定点

作者站长头像
站长
· 阅读数 5

Canvas的文字绘制已经有很多人写过了,这里只是对文字绘制的显示位置的归纳,过通自定义 Alignment 参数的使用从而避免对绘制文字大小的额外偏移计算。

先贴效果,一睹为快。

flutter 文字绘制与相对位置定点

基础参数的相对位置图例

代码实现: flutter 文字绘制与相对位置定点

相对位置解析
/// 文字绘制
extension StringCanvasExt on String {
  /// 文本绘制
  ///
  /// ```
  /// [offset]: 文字对齐点
  /// [alignment]: 文字相对 点[offset] 对齐的方式, 默认居中(文字中心与offset重叠)
  ///              eg: Alignment.bottomCenter 位于点offset中下方
  /// [maxLength]: 文字最大宽度
  /// [isDebugColor]: 是否显示背景色块
  /// ```
  draw(
    Canvas canvas,
    Offset offset, {
    TextStyle style = const TextStyle(fontSize: 12, color: Colors.black),
    Alignment alignment = Alignment.center,
    double? maxWidth,
    bool isDebugColor = false,
  }) {
    final text = TextPainter(
      text: TextSpan(
        text: this,
        style: style,
      ),
      // strutStyle: const StrutStyle(forceStrutHeight: true),
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr,
    );
    text.layout(maxWidth: maxWidth ?? double.infinity);
    final textSize = text.size;

    // 对文字本身做偏移
    final alignOffset = Offset(
            textSize.width / 2 * alignment.x, textSize.height / 2 * alignment.y)
        .translate(-textSize.width / 2, -textSize.height / 2);
    // 下面对位置偏移的操作,更容易理解
    // final alignOffset = Offset.zero
    //     .translate(-textSize.width / 2, -textSize.height / 2)
    //     .translate(textSize.width / 2 * alignment.x,
    //         textSize.height / 2 * alignment.y);
    
    // 绘制色块,方便调试
    if (!kReleaseMode && isDebugColor) {
      canvas.drawRect(
        (alignOffset + offset) & textSize,
        Paint()
          ..style = PaintingStyle.fill
          ..color = Colors.red.withOpacity(0.5),
      );
    }

    text.paint(canvas, alignOffset + offset);
  }
}


绘制代码中唯一需要注意的是 alignOffset 的值的计算含义:

  1. 校准 Alignment.center 的位置:

操作1: translate(-textSize.width / 2, -textSize.height / 2)

由于绘制默认布局起点为左上角 Offset(-1, -1) ,而我们传统意义上的 居中 为视图中心点 (size.width/2, size.height/2), 所以这里对计算值进行视图半宽高大小的偏移,以同步我们对传统意义上居中的理解。

  1. 通过对 Alignment(this.x, this.y) 值的进一步处理,实现布局的释义:

操作2: Offset( textSize.width / 2 * alignment.x, textSize.height / 2 * alignment.y)

通过 操作1 我们已经对渲染文本实现了绝对居中,现在结合 Alignment 的值只需要对 alignOffset 再进行一次位置偏移 操作2 就可以完成我们对布局的期望。

完成这两步后我们想要的结果就已经出来了。

换一个写法应该更容易理解:

final alignOffset = Offset.zero
    .translate(-textSize.width / 2, -textSize.height / 2)
    .translate(textSize.width / 2 * alignment.x,
        textSize.height / 2 * alignment.y);

实现还是比较简单,记录下方便以后查找。

简单封装的坐标系代码也在里面。

git: draw_text