如何在画布上绘制大尺寸文字?

时间:2013-01-26 21:24:16

标签: android android-canvas drawtext

我想在画布月份的文字垂直沿屏幕高度绘制。

Paint init:

   this.paint = new Paint();
   this.paint.setAntiAlias(true);
   this.paint.setDither(true);
   this.paint.setSubpixelText(true);
   this.paint.setColor(color_text_dark);
   this.paint.setTextAlign(Align.RIGHT);

图:

   // Set the scale to the widest month
   float scale = getHeight() / this.max_month_width;
   String month_string = FULL_MONTH_NAME_FORMATTER.
                         format(active_month_calendar.getTime());
   canvas.save();
   canvas.translate(getWidth(), 0);
   canvas.rotate(-90);
   canvas.scale(scale, scale);
   canvas.drawText(month_string, 0, 0, this.paint);
   canvas.restore();

结果在 hdpi 屏幕上看起来很不错,但在 xhdpi 一个上非常难看和像素化。

我在各种设备上做了更多测试,并了解结果取决于Android版本,而不是屏幕密度和分辨率。

代码在2.x平台上运行良好,但在4.0.3+上不起作用。假设,这里改变了Android绘图实现。 完整代码,您可以看到here

hdpi 版本 2.3.5 (同时测试 2.2

hdpi

xhdpi 版本 4.2 (同时测试 4.1 4.0.3

xhdpi

尝试绘制抗锯齿的不同变体,子像素文本无效。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:10)

问题在于您是以一种尺寸绘制文本并将结果缩放。一旦确定了文本的宽度,就应该使用对Paint.measureText()的调用,相应地通过Paint.setTextSize()调整大小。一旦它正确测量,然后你调用Canvas.drawText()。

另一种方法是根本不测量文本,只需立即调用:

paint.setTextSize(paint.getSize() * scale)

虽然不能保证文本适合这种情况。

你的其他变换调用都不应该导致插值,所以它应该给你非常清晰的线条。

修改

以下是代码示例和比较屏幕截图:

canvas.save();
canvas.scale(10, 10);
canvas.drawText("Hello", 0, 10, mTextPaint);
canvas.restore();
float textSize = mTextPaint.getTextSize();
mTextPaint.setTextSize(textSize * 10);
canvas.drawText("Hello", 0, 300, mTextPaint);
mTextPaint.setTextSize(textSize);

Your rendering method on top, mine on bottom

答案 1 :(得分:2)

我没有足够的声誉评论Krylez的优秀答案,但我想回复mcfly soft关于路径的评论/问题。

对于路径和文本,这个想法是一样的。不是缩放和平移画布,而是绘制路径,将相同的缩放和平移放入矩阵并将其传递给Path.transform:

// instead of this:
canvas.scale(sX, sY);
canvas.translate(trX, trY);
canvas.drawPath(path);

// do this:
matrix.postScale(sX, sY);
matrix.postTranslate(trX, trY);
path.transform(matrix);
canvas.drawPath(path);