draw text 文字对齐

最近画一个自定义 view,涉及到蛮多 draw text 的地方,算是把恼人的文字对齐大体熟悉了。

Android 在 draw 一段 text 的方法如下

1
public void drawText(String text, float x, float y, Paint paint)

方法有四个参数,除了 y 其他都蛮好理解的。那么 y 为什么难理解呢?因为我们不知道 y 定义的是哪里的位置?文字的顶部?底部?还是中间?其实我们是一头雾水。

下面一张图很好解释了 draw 一段文字垂直位置的说明。

上图中 baseline 是上面方法参数中的 y。如果 y 是 0,那么绘制文字时,根据上面的图,可以发现,这会导致文字几乎都绘制在了 0 像素以上区域,也就是 view 之外了。只剩下 baseline 到 bottom 之间的距离保持在 view 内。如果 y 是 canvas 的高度,那么 baseline 到 bottom 之间的区域就会在 view 之外。

Android 提供了一个 Paint.FontMetrics 类可以获取到上图 top / bottom 等值,top / bottom 都是相对于 baseline 的相对值,一般情况下,top 都是负数,bottom 都是正数。可以通过 Paint#getFontMetrics() 获取 Paint.FontMetrics.

1
2
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;

假设我们有个 canvas,关于绘制文字,可能有下列情况,我们一一分析。

1、垂直上对齐

上对齐是指文字区域的 top 对应 canvas 的顶端,即 top = 0。其实只需要把 baseline 下移 abs(top) 个像素即可.

1
canvas.drawText("demo text", 0, abs(top), paint);

2、垂直下对齐

和上对齐一样,这次要保证 bottom = canvas.getHeight(); 则 baseline = canvas.getHeight() - bottom.

1
canvas.drawText("demo text", 0, canvas.getHeight() - bottom, paint);

3、垂直居中对齐

这个咋一看有点难办,其实居中对齐可以转换成上对齐,或者下对齐,然后确定一个对齐线。

比如说,如果我们想采用上对齐来达到居中对齐。首先我们要先确定一个上对齐的对齐线。我们知道文字的高度是 bottom - top, 那么上对齐的线就是 alignLine = (canvasHeight - (bottom - top)) / 2,这样我们就可以依照这个对齐线来进行上对齐。

1
canvas.drawText("demo text", 0, canvas.getHeight() - (bottom - top) / 2 + abs(top));

4、水平居中对齐

考虑水平对齐,Paint 有个 measureText(String) 的方法可以获取要绘制的文字的预期宽度,这样根据文字宽度来调整 x 位置即可。

1
2
3
float textWidth = paint.measureText("demo text");
float x = canvas.getWidth() / 2 - textWidth / 2;
canvas.drawText("demo text", x, y, paint);