在某些指定的Rectangle中绘制文本拟合

时间:2011-01-05 07:33:19

标签: android text canvas drawing

使用画布,我想绘制一些适合某些指定矩形的短标签文本(1-2个字符)。 由于某些其他原因,我使用的缩放使得该重新纠缠的尺寸很小,即约为1.

我面临的问题是在绘制文本之前计算最佳(尽可能大,以使文本仍然适合)文本大小与Paint.setTextSize一起使用(我使用{{1} })。 为此我可以使用Canva.drawText()对象将一些常规字体尺寸作为浮点数或Paint.Fontmetrics来获取文本的边界框作为整数矩形。由于我使用的缩放,后者的整数边界框是不精确的,以便为我的目的计算最佳文本大小。

我需要的是一些方法来获得更高精度的文本边界框(例如getTextBounds(String text, int start, int end, Rect bounds)中的getStringBounds(String str, Graphics context)),但我找不到合适的方法。

2 个答案:

答案 0 :(得分:7)

我现在也忙于解决这个问题。

不幸的是我还没有设法安装原生源,但我很确定文本测量(getTextBounds()和measureText())与真正的文本输出有很大不同,特别是对于小字体(如在Moritz' screenshot中看到。 我想测量方法对char使用float宽度,而实际文本输出使用int(可能是由于性能)。如果您需要绝对精确的尺寸(例如自动调整大小),这当然会失败。 我用monospace字体进行了一些实验。此图显示了其中一些实验:

Android Autoscale experiments

这些实验中的文字比例是通过自动缩放来设定的。

在第一行,我创建了一个整数增量的框。这些匹配android文本输出。你看,最后一个密码与屏幕不匹配!

在第2行中,使用浮点增量创建了框。这些框更好地匹配屏幕,但它们与android文本输出不匹配!

在最后一行中,方框以浮点增量递增,文本由char以相同的增量输出char。盒子和字母都很完美。

在我的结论中,目前无法将Android文本输出设置为精确的宽度。问题似乎不是测量方法,这是足够精确的。问题似乎是,您无法通过setTextSize()设置精确的文本宽度。

请尝试以下方法重现:

    float width = 100; // define a width which should be achieved
    m_textPaint.setTextSize( 100 ); // set a text size surely big enough
    Rect r = new Rect();
    String s = new String("This is a test text");
    m_textPaint.getTextBounds( s, 0, s.length(), r ); // measure the text with a random size
    float fac = width / r.width(); // compute the factor, which will scale the text to our target width
    Log.i( "MyTestOutput", "current text width:" + r.width() );
    Log.i( "MyTestOutput", "wanted text width:" + width );
    Log.i( "MyTestOutput", "factor:" + fac );
    Log.i( "MyTestOutput", "expected result:" + (float) r.width() * fac );
    m_textPaint.setTextSize( m_textPaint.getTextSize() * fac );
    m_textPaint.getTextBounds( s, 0, s.length(), r ); // now final measurement: whats the real width?
    Log.i( "MyTestOutput", "real result:" + r.width() );

我得到了输出:

  

05-26 12:18:18.420:I / MyTestOutput(23607):当前文字宽度:1125

     

05-26 12:18:18.425:I / MyTestOutput(23607):想要文字宽度:100.0

     

05-26 12:18:18.425:I / MyTestOutput(23607):因素:0.08888889

     

05-26 12:18:18.425:I / MyTestOutput(23607):预期结果:100.0

     

05-26 12:18:18.430:I / MyTestOutput(23607):真实结果:94

所以在我看来,实现非常精确自动缩放文本的唯一方法是 a)通过测量和设置文本大小来自动调整它 b)通过char以自我计算的增量输出char。

不幸的是,这仅适用于等宽字体。对于其他字体,它会更复杂,但也可能。

答案 1 :(得分:1)

我几天前做过这样的事:See my blog

您可以使用StaticLayout

// bmp1 is a source bitmap (in that case 44x44px big).
// density is the screen density, you will need to retrieve it yourself as well.

canvas.drawBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.overlay_44x44), new Matrix(), null);

// Initialize using a simple Paint object.
final TextPaint tp = new TextPaint(WHITE);

// Save the canvas state, it might be re-used later.
canvas.save();

// Create a padding to the left & top.
canvas.translate(4*density, 4*density);

// Clip the bitmap now.
canvas.clipRect(new Rect(0, 0, bmp1.getWidth(),(int) (bmp1.getHeight() - (6*density))));

// Basic StaticLayout with mostly default values
StaticLayout sl = new StaticLayout(message, tp, bmp1.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
sl.draw(canvas);

// Restore canvas.
canvas.restore();