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
的值的计算含义:
- 校准
Alignment.center
的位置:
操作1: translate(-textSize.width / 2, -textSize.height / 2)
;
由于绘制默认布局起点为左上角 Offset(-1, -1)
,而我们传统意义上的 居中
为视图中心点 (size.width/2, size.height/2)
, 所以这里对计算值进行视图半宽高大小的偏移,以同步我们对传统意义上居中的理解。
- 通过对
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