测量在canvas上绘制的文本高度(Android)
任何直接测量文字高度的方法? 我现在做的方法是使用Paint的measureText()
来获取宽度,然后通过反复试验find一个值来获得一个近似的高度。 我也一直在搞FontMetrics
,但所有这些看起来像FontMetrics
近似方法。
我正在尝试针对不同的分辨率进行缩放。 我可以做到这一点,但我最终得到了很多计算繁琐的代码,以确定相对大小。 我讨厌它! 一定有更好的方法。
那么paint.getTextBounds() (对象方法)
@ bramp的答案是正确的 – 部分是因为它没有提到计算出来的边界将是最小的矩形,它包含完全隐含的开始坐标为0,0的文本。
这意味着,例如“Py”的高度将不同于“py”或“hi”或“oi”或“aw”的高度,因为像素方面它们需要不同的高度。
这绝不等于经典java中的FontMetrics。
虽然文字的宽度不是很大的痛苦,但高度是。
特别是,如果您需要垂直居中alignment绘制的文本,请尝试获取文本“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
垂直居中alignment文本意味着垂直居中alignment的边界矩形 – 这是不同的文本(大写,长字母等)。 但是我们实际上想要做的也是alignment渲染文本的基线,使它们不会出现高架或凹槽。 所以,只要我们知道最小的字母(例如“a”)的中心,我们就可以重新使用其余的文本的alignment方式。 这将中心alignment所有文本以及基线alignment它们。
有不同的方法来衡量的高度取决于你需要什么。
getTextBounds
如果你正在做的东西像精确地居中less量的固定文本,你可能想要getTextBounds
。 你可以像这样得到边界矩形
Rect bounds = new Rect(); mTextPaint.getTextBounds(mText, 0, mText.length(), bounds); int height = bounds.height();
正如你可以看到以下图像,不同的string会给不同的高度(以红色显示)。
这些不同的高度在某些情况下可能是不利的,无论文字是什么,只需要一个不变的高度。 看下一节。
Paint.FontMetrics
您可以从字体度量中计算字体的高度。 高度总是相同的,因为它是从字体获得的,而不是任何特定的文本string。
Paint.FontMetrics fm = mTextPaint.getFontMetrics(); float height = fm.descent - fm.ascent;
基线是文本所在的行。 下降通常是一个angular色将要到达的最远的angular色,而上升通常是angular色越过该angular线的最远的angular色。 要获得高度,你必须减去上升,因为它是一个负值。 (基线是y=0
, y
在屏幕上下降。)
看看下面的图片。 这两个string的高度是234.375
。
如果你想要的行高而不仅仅是文字的高度,你可以做到以下几点:
float height = fm.bottom - fm.top + fm.leading; // 265.4297
这些是行的bottom
和top
。 前导(行间距)通常为零,但是您应该添加它。
上面的图片来自这个项目 。 你可以玩弄它看看Font Metrics是如何工作的。
StaticLayout
为了测量多行文本的高度,你应该使用一个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();
高度是您在Paintvariables上设置的文本大小。
找出身高的另一种方法是
mPaint.getTextSize();
您可以使用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)
方法来绘制文本(包含在布局中)。
您必须使用从getTextBounds()
返回的Rect.width()
和Rect.Height()
。 这对我行得通。
如果有人仍然有问题,这是我的代码。
我有一个自定义视图是方形(宽度=高度),我想给它分配一个字符。 onDraw()
显示如何获得字符的高度,虽然我不使用它。 angular色将显示在视图的中间。
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(); } }