测量要在 Canvas 上绘制的文本高度(Android)

有没有直接测量文本高度的方法? 我现在做的方法是使用油漆的 measureText()得到宽度,然后通过尝试和错误找到一个值得到一个近似的高度。我也一直在使用 FontMetrics,但是所有这些方法看起来都很糟糕。

我试图按照不同的分辨率来衡量事物。我可以做到这一点,但是我最终得到的是非常冗长的代码,其中包含了大量确定相对大小的计算。我讨厌这样!肯定有更好的办法。

116606 次浏览

GetTextBounds ()(对象方法)呢

你必须使用从 getTextBounds()返回的 Rect.width()Rect.Height()。这对我来说很有效。

@ bramp 的回答是正确的——部分地,因为它没有提到计算的边界将是完全包含文本的最小矩形,隐式起始坐标为0,0。

这意味着,例如“ Py”的高度将不同于“ Py”或“ hi”或“ oi”或“ aw”的高度,因为它们在像素方面需要不同的高度。

这绝不等同于经典 Java 中的 FontMetrics。

虽然文本的宽度不太麻烦,但高度很麻烦。

特别是,如果您需要垂直居中对齐所绘制的文本,请尝试获得文本“ a”的边界(不带引号) ,而不是使用您打算绘制的文本。 对我有用。

我的意思是:

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG);


paint.setStyle(Paint.Style.FILL);
paint.setColor(color);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(textSize);


Rect bounds = new Rect();
paint.getTextBounds("a", 0, 1, bounds);


buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, paint);
// remember x >> 1 is equivalent to x / 2, but works much much faster

垂直居中对齐文本意味着垂直居中对齐边框-这是不同的文本(大写,长字母等)。但是我们实际上想要做的是对齐渲染文本的基线,这样它们就不会显得太高或有凹槽。因此,只要我们知道最小的字母(例如“ a”)的中心,我们就可以在其余的文本中重复使用它的对齐方式。这将中心对齐所有的文本以及基线对齐他们。

您可以使用 getTextSize ()方法简单地获取 Paint 对象的文本大小。 例如:

Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
//use densityMultiplier to take into account different pixel densities
final float densityMultiplier = getContext().getResources()
.getDisplayMetrics().density;
mTextPaint.setTextSize(24.0f*densityMultiplier);


//...


float size = mTextPaint.getTextSize();

您可以使用 android.text.StaticLayout类来指定所需的边界,然后调用 getHeight()。可以通过调用其 draw(Canvas)方法绘制文本(包含在布局中)。

如果还有人有问题,这是我的代码。

我有一个自定义视图,它是正方形的(width = height) ,我想为它分配一个字符。onDraw()显示了如何获得字符的高度,虽然我没有使用它。字符将显示在视图的中间。

public class SideBarPointer extends View {


private static final String TAG = "SideBarPointer";


private Context context;
private String label = "";
private int width;
private int height;


public SideBarPointer(Context context) {
super(context);
this.context = context;
init();
}


public SideBarPointer(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}


public SideBarPointer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
init();
}


private void init() {
//        setBackgroundColor(0x64FF0000);
}


@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);


height = this.getMeasuredHeight();
width = this.getMeasuredWidth();


setMeasuredDimension(width, width);
}


protected void onDraw(Canvas canvas) {
float mDensity = context.getResources().getDisplayMetrics().density;
float mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity;


Paint previewPaint = new Paint();
previewPaint.setColor(0x0C2727);
previewPaint.setAlpha(200);
previewPaint.setAntiAlias(true);


Paint previewTextPaint = new Paint();
previewTextPaint.setColor(Color.WHITE);
previewTextPaint.setAntiAlias(true);
previewTextPaint.setTextSize(90 * mScaledDensity);
previewTextPaint.setShadowLayer(5, 1, 2, Color.argb(255, 87, 87, 87));


float previewTextWidth = previewTextPaint.measureText(label);
//        float previewTextHeight = previewTextPaint.descent() - previewTextPaint.ascent();
RectF previewRect = new RectF(0, 0, width, width);


canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint);
canvas.drawText(label, (width - previewTextWidth)/2, previewRect.top - previewTextPaint.ascent(), previewTextPaint);


super.onDraw(canvas);
}


public void setLabel(String label) {
this.label = label;
Log.e(TAG, "Label: " + label);


this.invalidate();
}
}

高度是您在 Paint 变量上设置的文本大小。

另一种测量高度的方法是

mPaint.getTextSize();

根据您的需要,有不同的测量高度的方法。

# 1 获取文本界限

如果您正在做的事情,如精确居中少量的固定文本,您可能需要 getTextBounds。你可以得到像这样的边界矩形

Rect bounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mText.length(), bounds);
int height = bounds.height();

正如您在下面的图像中看到的,不同的字符串将给出不同的高度(以红色显示)。

enter image description here

在某些情况下,这些不同的高度可能是一个缺点,因为无论文本是什么,您都需要一个恒定的高度。请参阅下一节。

# 2 油漆 FontMetrics

您可以根据字体度量来计算字体的高度。高度总是相同的,因为它是从字体获得的,而不是任何特定的文本字符串。

Paint.FontMetrics fm = mTextPaint.getFontMetrics();
float height = fm.descent - fm.ascent;

基线是文本所在的行。下降通常是一个字符在线下走得最远,而上升通常是一个字符在线上走得最远。为了得到高度,你必须减去上升,因为它是一个负值。(基线是 y=0,而 y在屏幕上呈下降趋势。)

看下图,两个字符串的高度都是 234.375

enter image description here

如果希望使用行高而不仅仅是文本高,可以执行以下操作:

float height = fm.bottom - fm.top + fm.leading; // 265.4297

这些是线路的 bottomtop。前导(行间距)通常为零,但无论如何都应该添加它。

上面的图片来自 这个项目。你可以玩玩它,看看字体度量是如何工作的。

# 3 静态布局

为了测量多行文本的高度,您应该使用 StaticLayout。我在 这个答案中详细讨论过,得到这个高度的基本方法是这样的:

String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text.";


TextPaint myTextPaint = new TextPaint();
myTextPaint.setAntiAlias(true);
myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
myTextPaint.setColor(0xFF000000);


int width = 200;
Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL;
float spacingMultiplier = 1;
float spacingAddition = 0;
boolean includePadding = false;


StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding);


float height = myStaticLayout.getHeight();