2011-02-05 78 views
41

目标:纯粹Canvas上的Android> = 1.6。如何垂直排列文本?

假设我想写一个函数,它将绘制一个(宽度,高度)大的红色矩形,然后在里面绘制一个黑色的文本。我希望文字在矩形的中心可视化。所以让我们尝试:

void drawHelloRectangle(Canvas c, int topLeftX, 
     int topLeftY, int width, int height) { 
    Paint mPaint = new Paint(); 
    // height of 'Hello World'; height*0.7 looks good 
    int fontHeight = (int)(height*0.7); 

    mPaint.setColor(COLOR_RED); 
    mPaint.setStyle(Style.FILL); 
    c.drawRect(topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint); 

    mPaint.setTextSize(fontHeight); 
    mPaint.setColor(COLOR_BLACK); 
    mPaint.setTextAlign(Align.CENTER); 
    c.drawText("Hello World", topLeftX+width/2, ????, mPaint); 
} 

现在,我不知道要放什么的drawText的论证通过????标记,即我不知道该怎么垂直对齐文本。

喜欢的东西

???? = topLeftY + height/2 + fontHeight/2 - fontHeight/8;

似乎工作或多或少好,但必须有更好的方法。

+18

每次您在问题标题中放入* Android *时,小猫都会死亡,请不要这样做。谢谢。 – 2011-02-05 20:20:57

回答

83

实例来集中在cxcy

private final Rect textBounds = new Rect(); //don't new this up in a draw method 

public void drawTextCentred(Canvas canvas, Paint paint, String text, float cx, float cy){ 
    paint.getTextBounds(text, 0, text.length(), textBounds); 
    canvas.drawText(text, cx - textBounds.exactCenterX(), cy - textBounds.exactCenterY(), paint); 
} 

为什么不height()/2f工作一样吗?

exactCentre() = (top + bottom)/2f

height()/2f = (bottom - top)/2f

这些将仅产生相同的结果时top0。对于所有尺寸的某些字体或某些尺寸的其他字体,情况可能如此,但不适用于所有尺寸的所有字体。

9

使用mPaint.getTextBounds()您可以询问绘制时文本的大小,然后使用该信息可以计算出要绘制的文本的位置。

+2

getTextBounds()属于Paint而不是Canvas – Melllvar 2011-06-12 00:59:04

+4

请记住,当您说垂直居中的文本时,您可能意味着围绕字符的上升部分,而不是基线。当您使用Align.CENTER绘图时,Y坐标将以字符基线为中心。 – 2012-04-22 18:38:13

+0

@CameronLowellPalmer你能详细解释一下吗? – Peterdk 2013-06-15 19:31:11

21

基于steelbytes的回应,更新的代码看起来是这样的:

void drawHelloRectangle(Canvas c, int topLeftX, int topLeftY, int width, int height) { 
    Paint mPaint = new Paint(); 
    // height of 'Hello World'; height*0.7 looks good 
    int fontHeight = (int)(height*0.7); 

    mPaint.setColor(COLOR_RED); 
    mPaint.setStyle(Style.FILL); 
    c.drawRect(topLeftX, topLeftY, topLeftX+width, topLeftY+height, mPaint); 

    mPaint.setTextSize(fontHeight); 
    mPaint.setColor(COLOR_BLACK); 
    mPaint.setTextAlign(Align.CENTER); 
    String textToDraw = new String("Hello World"); 
    Rect bounds = new Rect(); 
    mPaint.getTextBounds(textToDraw, 0, textToDraw.length(), bounds); 
    c.drawText(textToDraw, topLeftX+width/2, topLeftY+height/2+(bounds.bottom-bounds.top)/2, mPaint); 
} 
24
textY = topLeftY + height/2 - (mPaint.descent() + mPaint.ascent())/2 

从 “基准” 的距离 “中心” 应该是-(mPaint.descent() + mPaint.ascent())/2

5
public static PointF getTextCenterToDraw(String text, RectF region, Paint paint) { 
    Rect textBounds = new Rect(); 
    paint.getTextBounds(text, 0, text.length(), textBounds); 
    float x = region.centerX() - textBounds.width() * 0.4f; 
    float y = region.centerY() + textBounds.height() * 0.4f; 
    return new PointF(x, y); 
} 

用法:

PointF p = getTextCenterToDraw(text, rect, paint); 
canvas.drawText(text, p.x, p.y, paint); 
13

由于在Y处绘制文本意味着文本的基线将结束Ÿ像素向下从原点,你需要的时候你要(width, height)尺寸的矩形内文本居中做的是:

paint.setTextAlign(Paint.Align.CENTER); // centers horizontally 
canvas.drawText(text, width/2, (height - paint.ascent())/2, paint); 

请记住,上升是负的(这解释了负号)。

这不考虑下降,这通常是你想要的(上升通常是高于基线的高度)。