关于把文本绘制到控件中间的问题

2020-08-10  本文已影响0人  飞奔吧牛牛

只需要搞懂这两个方法。别看源码了,这两个方法调到最后都跑native那边去了。

Paint.getFontMetricsInt();

这个方法提供了文字排版的几个重要数据,top,ascent,descent,bottom,leading。最后一个leading不知道什么用,据说和额外边距有关,即上一行text的bottom距下一行text的top的距离,这里暂且用不到。

绘制文本时,调用canvas.drawText(String text, float x, float y, Paint paint);
值得注意的是,这里的x,y是文字的左下角的某个位置,具体如下图所示:


image.png

看到了吗,就那个小红点。


image.png
这里的y所在的线大家都叫它baseline。
现在关于Paint.getFontMetricsInt();所得到的这几条线全画出来是这个样子。多了个‘a’?嗯,我故意的。
image.png

这五条线依次是top,ascent,baseline,descent,bottom。
其中ascent和descent之间的区域是常见字符的范围,中文都是方块字,英文也还算规矩,一般不会超出这个区域。
这样文字所占的高度就可以拿到了:descent-ascent。也有人用bottom-top的。

Paint.getTextBounds(String text, int start, int end, Rect bounds);

刚开始拿到这个bounds,看到里面的数据也是一脸懵比。其实,它也以原点为基础,得到文字绝对大小的所在区域。


image.png

这两个方法研究透彻之后,要把一个文本绘制在一个区域的中间,要解决的就是一个数学问题了,即计算原点应该放到哪里。这里直接给出代码吧。


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();

        drawText(canvas, width, height);
    }

    private void drawText(Canvas canvas, int width, int height) {
        //获取起点x坐标
        mPaint.getTextBounds(mText, 0, mText.length(), bounds);
        float startX = (width - bounds.width()) / 2.0f;
        //获取起点y坐标
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        int baseline = (height - fontMetrics.descent - fontMetrics.ascent) / 2;
        //绘制text
        canvas.drawText(mText, startX, baseline, mPaint);
        
        //绘制baseline
        canvas.drawLine(0, baseline, width, baseline, mPaint);

        //绘制top
        float top = baseline + fontMetrics.top;
        canvas.drawLine(0, top, width, top, mPaint);
        //绘制ascent
        float ascent = baseline + fontMetrics.ascent;
        canvas.drawLine(0, ascent, width, ascent, mPaint);
        //绘制descent
        float descent = baseline + fontMetrics.descent;
        canvas.drawLine(0, descent, width, descent, mPaint);
        //绘制bottom
        float bottom = baseline + fontMetrics.bottom;
        canvas.drawLine(0, bottom, width, bottom, mPaint);

        //绘制bounds区域
        float rectLeft = startX + bounds.left;
        float rectRight = startX + bounds.right;
        float rectTop = baseline + bounds.top;
        float rectBottom = baseline + bounds.bottom;
        //top线
        canvas.drawLine(rectLeft, rectTop, rectRight, rectTop, mPaint);
        //left线
        canvas.drawLine(rectLeft, rectTop, rectLeft, rectBottom, mPaint);
        //right线
        canvas.drawLine(rectRight, rectTop, rectRight, rectBottom, mPaint);
        //bottom线
        canvas.drawLine(rectLeft, rectBottom, rectRight, rectBottom, mPaint);

        //绘制原点
        mPaint.setStrokeWidth(3);
        mPaint.setColor(Color.RED);
        canvas.drawPoint(startX, baseline, mPaint);
    }
上一篇下一篇

猜你喜欢

热点阅读