2011-01-05 65 views
4

使用画布,我想绘制一些适合某个指定矩形的简短标签文本(1-2个字符)。 由于其他一些原因,我使用的缩放比例是这样的,使得这个rec​​angle的尺寸很小,即大约1.在某些指定的矩形中绘制文本拟合

我面临的问题是计算最优(尽可能大,以便文本仍然适合)文本大小使用Paint.setTextSize之前绘制文本(我使用Canva.drawText())。 为此,我可以使用​​对象将一些常规字体维度作为浮点数获取,或者将getTextBounds(String text, int start, int end, Rect bounds)获得文本的边界框作为整数矩形。由于我使用的缩放比例,后者的整数边界框不准确,因此无法为我的目的计算最佳文本大小。

我需要的是一些方法来获得更高精度的文本的边界框(即java.awt.FontMetrics中的getStringBounds(String str, Graphics context)),但我没有找到合适的方法。

回答

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(); 
+0

对不起,我看到我的原始问题不是很精确。问题不是文本布局(文本长度只有1-2个字符),而是要计算最佳文本大小。 – 2011-01-05 08:40:08

7

我现在还忙于这个问题。

不幸的是,我还没有设法安装本地源代码,但我很确定文本测量(getTextBounds()和measureText())与真实文本输出差异很大,特别是对于小字号(如在Moritz' screenshot中看到的)。 我想测量方法使用一个字符的浮点宽度,而实际的文本输出使用int(可能是因为性能)。如果您需要绝对精确的尺寸(例如autosize),这当然会失败。 我用等宽字体做了一点实验。此图显示了其中一些实验:

Android Autoscale experiments

这些实验中的文本比例是通过自动缩放设置的。

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

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

在最后一行中,这些方框增加了一个浮点增量,并且文本通过相同的增量由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十二时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

12月5日至26日:18:18.425:I/MyTestOutput(23607):预期的结果:100.0

12月5日至26日:18:18.430:我/ MyTestOutput(23607):实际结果:94

所以在我看来,唯一的通过测量和设置文本大小 来自动缩放它b)通过自我计算的增量输出char字符,通过char获得非常精确的自动缩放文本。

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