在缩放画布上测量文本

7

我一直在苦恼文本测量和缩放画布的问题。

当画布未缩放时,getTextBounds和measureText可以提供准确的结果。但是,当画布被缩放后,这两种方法都不能提供与打印文本实际大小相匹配的结果。

为了测试,我创建了一个继承自View的子类,并使用以下onDraw方法:

final float scaling = 0.51f;
final int fontSize = 50;

canvas.scale(scaling, scaling);
font = Typeface.create("Arial", Typeface.NORMAL);

Paint paint = new Paint();
paint.setColor(0xff4444ff);
paint.setTypeface(font);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);

int x = 10;
int y = 100;
final String text = "Lorem ipsum dolor sit amet, consectetur adipisici elit...";
canvas.drawText(text, x, y, paint);

// draw border using getTextBounds

paint.setColor(0xffff0000);
paint.setStyle(Paint.Style.STROKE);
paint.setTypeface(font);
paint.setTextSize(fontSize);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
bounds.offset(x, y);
paint.setColor(0x80ffff00);
canvas.drawRect(bounds, paint);

// draw border using measureText

float w = paint.measureText(text);
bounds.left = x;
bounds.right = (int) Math.ceil(bounds.left + w);
bounds.top -= 10;
bounds.bottom += 10;
paint.setColor(0x8000ffff);
paint.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 0));
canvas.drawRect(bounds, paint);

对于缩放比例为0.5,我得到了以下输出: canvas scaling 0.5 对于缩放比例为0.51,则显示如下结果: canvas scaling 0.51 黄色实线边框标记的是从getTextBounds返回的矩形,虚线青色矩形是使用measureText所返回宽度渲染出来的。
正如您所看到的,当缩放比例为0.5时,文本比测量的尺寸要小,而当缩放比例为0.51时,绘制的文本比测量的尺寸要大得多。
任何帮助都将不胜感激!
2个回答

4

好的,我找到了解决问题的方法。

问题在于Paint不知道Canvas的缩放比例。因此measureText和getTextBounds会提供未经缩放的结果。但是由于字体大小不是线性缩放的(然而绘制的矩形确实线性缩放的),因此您需要手动修复该效果。

因此解决方案如下:

// paint the text as usual
Paint paint = new Paint();
paint.setTypeface(font);
paint.setTextSize(fontSize);
canvas.drawText(text, x, y, paint);


// measure the text using scaled font size and correct the scaled value afterwards
Paint paint = new Paint();
paint.setTypeface(font);
paint.setTextSize(fontSize * scaling);
float w = paint.measureText(text) / scaling;

0

使用Mono for Android时,我必须像这样使用显示度量:

public override System.Drawing.SizeF MeasureString(MyFont f, string text)
{
  Rect r = new Rect();

  f.DrawingFont.GetTextBounds(text, 0, text.Length, r);

  //Manual scaling using DisplayMetrics due to Android
  //issues for compatibility with older versions
  Android.Util.DisplayMetrics metrics = new Android.Util.DisplayMetrics();
  GetDisplay.GetMetrics(metrics);

  return new System.Drawing.SizeF(r.Width(), r.Height() * metrics.Density);
}

f.DrawingFont 是一个 Android.Text.TextPaint GetDisplay 方法:

private Display GetDisplay()
{
  return this.GetSystemService(Android.Content.Context.WindowService).JavaCast<Android.Views.IWindowManager>().DefaultDisplay;
}

而在Java中,相同的方法是:

private Display getDisplay() {
    return ((WindowManager) getContext().getSystemService(
            Context.WINDOW_SERVICE)).getDefaultDisplay();
}

你的修正总是应用的,但是没有考虑到画布的缩放值,对吧?我实际上并不认为边界矩形的计算是错误的,而是字体渲染代码没有根据画布缩放选择正确的字体大小... - P.Melch
是的,通常需要计算文本尺寸而不缩放画布。 - Narcís Calvet
忘了提到这主要用于在画布中定位文本,知道确切的尺寸和位置是必要的。 - Narcís Calvet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接