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

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

先贴效果,一睹为快。

基础参数的相对位置图例

代码实现:

相对位置解析
arduino 复制代码
/// 文字绘制
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 就可以完成我们对布局的期望。

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

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

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

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

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

Github: draw_text

相关推荐
明似水6 小时前
Flutter 弹窗队列管理:支持优先级的线程安全通用弹窗队列系统
javascript·安全·flutter
坚果的博客12 小时前
坚果派已适配的鸿蒙版flutter库【持续更新】
flutter·华为·开源·harmonyos
ak啊17 小时前
Flutter项目架构设计方案
flutter
JarvanMo20 小时前
在Dart泛型中应该优先使用dynamic还是Object?
前端·flutter·dart
恋猫de小郭20 小时前
Flutter 在 Dart 3.8 开始支持 Null-Aware Elements 语法,自动识别集合里的空元素
android·前端·flutter
恋猫de小郭1 天前
Flutter Widget IDE 预览新进展,开始推进落地发布
android·前端·flutter
Ya-Jun1 天前
常用第三方库:flutter_boost混合开发
android·flutter·ios
技术蔡蔡1 天前
全面解读Flutter状态管理框架signals使用,知其然和所以然
flutter·dart
pengyu1 天前
【Flutter 状态管理 - 柒】 | InheritedWidget:藏在组件树里的"魔法"✨
android·flutter·dart
肥肥呀呀呀2 天前
flutter 小知识
flutter