【发布时间】:2012-08-23 09:17:15
【问题描述】:
我想使用.drawtext在一定宽度的canvas上绘制文本
例如,无论输入文本是什么,文本的宽度都应始终为400px。
如果输入文本较长,则会减小字体大小,如果输入文本较短,则会相应增加字体大小。
【问题讨论】:
标签: java android android-canvas
我想使用.drawtext在一定宽度的canvas上绘制文本
例如,无论输入文本是什么,文本的宽度都应始终为400px。
如果输入文本较长,则会减小字体大小,如果输入文本较短,则会相应增加字体大小。
【问题讨论】:
标签: java android android-canvas
Michael Scheper's solution 看起来不错,但它对我不起作用,我需要获得可以在我的视图中绘制的最大文本大小,但这种方法取决于您设置的第一个文本大小,每次设置不同的尺寸你会得到不同的结果,不能说它在每种情况下都是正确的答案。
所以我尝试了另一种方法:
private float calculateMaxTextSize(String text, Paint paint, int maxWidth, int maxHeight) {
if (text == null || paint == null) return 0;
Rect bound = new Rect();
float size = 1.0f;
float step= 1.0f;
while (true) {
paint.getTextBounds(text, 0, text.length(), bound);
if (bound.width() < maxWidth && bound.height() < maxHeight) {
size += step;
paint.setTextSize(size);
} else {
return size - step;
}
}
}
这很简单,我增加文本大小,直到文本矩形绑定尺寸足够接近 maxWidth 和 maxHeight,要减少循环重复,只需将 step 更改为更大的值(准确性与速度),也许这不是实现这一目标的最佳方式,但它确实有效。
【讨论】:
float desiredTextSize = testTextSize * desiredWidth / bounds.width(); 返回一个可接受的值,但不一定是最大尺寸,毫无疑问,您的解决方案更有效,但我认为结果非常依赖desiredWidth,并不完全符合我的需要,问候
float desiredTextSize = testTextSize * Math.min(desiredWidth / bounds.width(), desiredHeight / bounds.height())。无论如何,请注意解决方案中的整数;它们会导致你的浮点数只保存整数值,这可能不像你需要的那么精确。
这里有一个更有效的方法:
/**
* Sets the text size for a Paint object so a given string of text will be a
* given width.
*
* @param paint
* the Paint to set the text size for
* @param desiredWidth
* the desired width
* @param text
* the text that should be that width
*/
private static void setTextSizeForWidth(Paint paint, float desiredWidth,
String text) {
// Pick a reasonably large value for the test. Larger values produce
// more accurate results, but may cause problems with hardware
// acceleration. But there are workarounds for that, too; refer to
// http://stackoverflow.com/questions/6253528/font-size-too-large-to-fit-in-cache
final float testTextSize = 48f;
// Get the bounds of the text, using our testTextSize.
paint.setTextSize(testTextSize);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
// Calculate the desired size as a proportion of our testTextSize.
float desiredTextSize = testTextSize * desiredWidth / bounds.width();
// Set the paint for that size.
paint.setTextSize(desiredTextSize);
}
然后,您需要做的就是setTextSizeForWidth(paint, 400, str);(400 是问题中的示例宽度)。
为了提高效率,您可以将Rect 设为静态类成员,从而避免每次都对其进行实例化。但是,这可能会引入并发问题,并且可能会妨碍代码清晰。
【讨论】:
static 时,无论有多少类实例,每个JVM 都只会有一个副本。但是对于非静态方法,类的每个实例都有一个副本,因此您可以拥有多个局部变量副本,并且我相信字节码本身也是如此。我承认这在你的 Android 应用程序中可能是相当学术的,如果你只是创建一个你放置这个代码的类的实例,但这是一个好习惯。我强烈推荐 Bloch 的书以获取更多信息。
setTextSizeForWidth 放入其中,您的应用程序具有三个这样的小部件。如果您的小部件的类使此方法成为静态,则将有一个副本。如果没有,那就是三个。三个副本一次只能使用一个,但是每次都会为两个floats分配新的内存,直到垃圾回收才会释放。同样,在这种情况下是次要的,但对于较大对象的较大集合,它很快就会导致问题。
试试这个:
/**
* Retrieve the maximum text size to fit in a given width.
* @param str (String): Text to check for size.
* @param maxWidth (float): Maximum allowed width.
* @return (int): The desired text size.
*/
private int determineMaxTextSize(String str, float maxWidth)
{
int size = 0;
Paint paint = new Paint();
do {
paint.setTextSize(++ size);
} while(paint.measureText(str) < maxWidth);
return size;
} //End getMaxTextSize()
【讨论】:
size / 2?猜猜我现在想不出一个很好的理由,但size - 1 对我来说更有意义:/
-1 并认为我没有得到我想要的。
size 而不是size/2 请编辑您的答案。
if (str == null || str.trim().length() == 0) return 0;