Android:在Canvas上测量文本高度

8

我目前正在渲染位图,然后想将其发送到移动打印机。然而,我无法测量文本的高度,以便适当地提高y位置。

我的基本位图/画布/绘画配置如下(字体大小为16,位图尺寸为200x400(宽x高):

public MyRenderer() {
    // Initialize bitmap
    bitmap = Bitmap.createBitmap(200, 400, Bitmap.Config.ARGB_8888);

    // Initialize canvas
    canvas = new Canvas(bitmap);

    // Initialize brush (Paint instance)
    brush = new Paint();
    brush.setTextSize(16);
    brush.setTypeface(Typeface.SANS_SERIF);
    brush.setColor(Color.BLACK);
    brush.setStyle(Paint.Style.FILL);
    brush.setAntiAlias(true);
    brush.setTextAlign(Align.LEFT);
}

到目前为止一切都很好,现在我想做的是:如果我使用Paint的drawText方法,我需要提供x和y坐标。对于x来说,它是零(假设文本左对齐),但是对于y来说,我必须计算我打印的每个文本的高度并将其相加,以便我可以跟踪我的当前y位置。
这就是奇怪的地方:我正在使用以下方法确定文本的高度(使用之前初始化的Paint对象 - 它被称为“brush”):
public int measureHeight(String text) {
    Rect result = new Rect();
    // Measure the text rectangle to get the height
    brush.getTextBounds(text, 0, text.length(), result);
    return result.height();
}

上述方法对以下文本返回以下值:
1. "Hello World" 返回高度为12 2. "A camera instance can be used to compute 3D transformations and generate a matrix." 返回高度为16 3. "Introducing Android Design: The place to learn about principles, building blocks, and patterns for creating world-class Android user interfaces. Whether you're a UI professional or a developer playing that role, these docs show you how to make good design decisions, big and small." 返回高度为16 我理解第二和第三个的高度比第一个大,但如果一行的高度为12(如第一个),那么多行的高度为16就没有意义了吗?
我错过了什么吗?有一个方便的方法可以测量文本的宽度(使用paint实例并调用measureText("myText")),这个方法非常完美,但是当涉及到高度时,我感到困惑,因为上面给出的结果对我来说毫无意义。
编辑
我知道getTextBounds可能不会自动换行多行文本,这没关系,我已经编写了一个拆分文本的方法,但即使它只测量一行,上述长度值仍然似乎不太可能。
2个回答

17

我认为这是因为"compute"中的“p”字母向下延伸超出了基线,而“Hello World”的字母都在基线以上。

由于行距不应该取决于文本具体包含哪些字母,因此您可能需要使用Paint.FontMetrics,该对象可以通过Paint.getFontMetrics()方法获得。计算descent - ascent + leading以获取推荐的基线距离(因为ascent的值为负数)。


我按照你的计算方法,计算了上述三个文本的基线距离,结果总是返回19。这是否意味着,如果我将19作为高度,下一行仍有足够的空间不会与当前行重叠?非常感谢您的帮助! - AgentKnopf
这是字体的一个特性,您不必为不同的文本重复计算它。您希望距离始终相同,无论您的文本由哪些字符组成。是的,行不会重叠。 - devconsole
非常感谢 - 这就是我所做的,现在呈现我的位图就可以正常工作了 :) 。 我在 MyRenderer 的构造函数中初始化了 “行高” 一次。 - AgentKnopf
8
更简单的说,Paint.getFontSpacing()方法。 - devconsole

5

在被接受的答案中存在一个小错误。如果您想要获取文本的高度,应该使用

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float textHeight = fm.descent - fm.ascent;

如果您想要行高,您应该使用

float lineHeight = fm.bottom - fm.top + fm.leading;

行距是可选的行间距,因此如果您需要获取行高,则可以包括它。但是,如果您只想要文本高度,则可以省略它。

注意

  • 我从未看到leading不是0,并且据我所知,在TextView源代码(及其相关的{{link2:Layout}},{{link3:StaticLayout}}等)中甚至似乎被忽略。如果我错了,请纠正我。因此,在计算行高时,将其排除在外可能是安全的,但我对此并不完全确定。

另请参阅


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接