Measuring text height to be drawn on Canvas ( Andr

2019-01-04 06:07发布

Any straight forward way to measure the height of text? The way I am doing it now is by using Paint's measureText() to get the width, then by trial and error finding a value to get an approximate height. I've also been messing around with FontMetrics, but all these seem like approximate methods that suck.

I am trying to scale things for different resolutions. I can do it, but I end up with incredibly verbose code with lots of calculations to determine relative sizes. I hate it! There has to be a better way.

8条回答
We Are One
2楼-- · 2019-01-04 06:19

@bramp's answer is correct - partially, in that it does not mention that the calculated boundaries will be the minimum rectangle that contains the text fully with implicit start coordinates of 0, 0.

This means, that the height of, for example "Py" will be different from the height of "py" or "hi" or "oi" or "aw" because pixel-wise they require different heights.

This by no means is an equivalent to FontMetrics in classic java.

While width of a text is not much of a pain, height is.

In particular, if you need to vertically center-align the drawn text, try getting the boundaries of the text "a" (without quotes), instead of using the text you intend to draw. Works for me...

Here's what I mean:

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

Vertically center aligning the text means vertically center align the bounding rectangle - which is different for different texts (caps, long letters etc). But what we actually want to do is to also align the baselines of rendered texts, such that they did not appear elevated or grooved. So, as long as we know the center of the smallest letter ("a" for example) we then can reuse its alignment for the rest of the texts. This will center align all the texts as well as baseline-align them.

查看更多
够拽才男人
3楼-- · 2019-01-04 06:20

You could use the android.text.StaticLayout class to specify the bounds required and then call getHeight(). You can draw the text (contained in the layout) by calling its draw(Canvas) method.

查看更多
聊天终结者
4楼-- · 2019-01-04 06:21

The height is the text size you have set on the Paint variable.

Another way to find out the height is

mPaint.getTextSize();
查看更多
劳资没心,怎么记你
5楼-- · 2019-01-04 06:25

What about paint.getTextBounds() (object method)

查看更多
我想做一个坏孩纸
6楼-- · 2019-01-04 06:30

You can simply get the text size for a Paint object using getTextSize() method. For example:

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();
查看更多
Evening l夕情丶
7楼-- · 2019-01-04 06:32

If anyone still has problem, this is my code.

I have a custom view which is square (width = height) and I want to assign a character to it. onDraw() shows how to get height of character, although I'm not using it. Character will be displayed in the middle of view.

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();
    }
}
查看更多
登录 后发表回答