跳转至

文字位置信息

准备基础类BaseView,继承View类。

public class BaseView extends View {
    static final int LINE_OFFSET = 60;

    protected Paint notePaint = new Paint();
    protected Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    protected Rect textRect = new Rect();

    public BaseView(Context context) {
        this(context, null);
    }

    public BaseView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}
BaseView里准备了2个画笔。

绘制文字的方法canvas.drawText,需要指定字符串,绘制起始坐标,画笔paint。

canvas.drawText(text, x, y, textPaint);

起始坐标的y值所在横线在后面也称为 baseline 。

获取文字边界

从图中可以看到文字的部分笔画是可以超出边线的。比如开头的j和结尾的r字符。

使用Paint.getTextBounds方法获取文字的边界。

textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // 获取text边界

绘制上图的部分代码

private void drawBounds(Canvas canvas, float tx, float ty, String onShowText) {
    canvas.drawText(onShowText, tx, ty, textPaint); // 写字
    textPaint.getTextBounds(onShowText, 0, onShowText.length(), textRect); // 获取text边界

    notePaint.setStrokeWidth(3);
    notePaint.setColor(Color.parseColor("#EF6C00"));

    // 左边线
    canvas.drawLine(tx, ty - textRect.height() - LINE_OFFSET, tx, ty + LINE_OFFSET, notePaint);

    // 右边线
    canvas.drawLine(tx + textRect.width(), ty - textRect.height() - LINE_OFFSET, tx + textRect.width(), ty + LINE_OFFSET, notePaint);

    notePaint.setColor(Color.parseColor("#FF0277BD"));
    // 上边线
    canvas.drawLine(tx - LINE_OFFSET, ty - textRect.height(), tx + textRect.width() + LINE_OFFSET, ty - textRect.height(), notePaint);

    notePaint.setColor(Color.parseColor("#00695C"));
    // y - baseline
    canvas.drawLine(tx - LINE_OFFSET, ty, tx + textRect.width() + LINE_OFFSET, ty, notePaint);
}

获取text尺寸信息

需要使用Paint.FontMetrics类。它有5个属性

属性 介绍
top 从baseline到最高的文字顶部的最大距离
ascent 单行距(singled spaced)时,baseline上方空间的推荐距离
descent 单行距时,baseline下方空间的推荐距离
bottom baseline到最下方字符的最大距离
leading 多行文字之间推荐使用的额外空间

使用Paint.getFontMetrics()方法获取Paint.FontMetrics

Paint.FontMetrics fm = textPaint.getFontMetrics();

注意,topascent是负值。

绘制上图的方法

private void drawFontMetrics(Canvas canvas, float x, float y, String text) {
    canvas.drawText(text, x, y, textPaint);
    textPaint.getTextBounds(text, 0, text.length(), textRect);
    Paint.FontMetrics fm = textPaint.getFontMetrics();

    notePaint.setStrokeWidth(1);
    notePaint.setColor(Color.BLACK);
    canvas.drawText(String.format(Locale.CHINA, "top:%.2f, bottom:%.2f", fm.top, fm.bottom), x, y + notePaint.getTextSize() * 2.5f, notePaint);
    canvas.drawText(String.format(Locale.CHINA, "ascent:%.2f, descent:%.2f, leading:%.2f", fm.ascent, fm.descent, fm.leading), x, y + notePaint.getTextSize() * 4f, notePaint);

    notePaint.setColor(Color.parseColor("#FFD84315"));

    // fm top线
    canvas.drawLine(x - L_BIAS, y + fm.top, x + textRect.width() + L_BIAS, y + fm.top, notePaint);

    notePaint.setColor(Color.parseColor("#FF00695C"));

    // fm bottom线
    canvas.drawLine(x - L_BIAS, y + fm.bottom, x + textRect.width() + L_BIAS, y + fm.bottom, notePaint);

    notePaint.setColor(Color.parseColor("#4527A0"));

    // fm ascent线
    canvas.drawLine(x - L_BIAS, y + fm.ascent, x + textRect.width() + L_BIAS, y + fm.ascent, notePaint);

    notePaint.setColor(Color.parseColor("#0E0822"));

    // fm descent线
    canvas.drawLine(x - L_BIAS, y + fm.descent, x + textRect.width() + L_BIAS, y + fm.descent, notePaint);
}

对齐文字中间

有了上面的基础,我们可以很快知道如何实现文字“居中对齐”。将文字的水平中心线或竖直中心线对齐到某个点。

例如绘制一个平面坐标系

绘制出2个坐标轴,然后绘制上刻度,并写上数值。 数值文字对应到刻度相应的位置上。我们主要使用Paint.getTextBounds获取到文字的尺寸信息,再计算出合适的位置。

private void drawChart(Canvas canvas) {
    final float x0 = 100;
    final float y0 = 300; // 原点在画布上的坐标
    final float halfLine = 5; // 刻度长度的一半

    textPaint.setColor(Color.BLACK);
    textPaint.setTextSize(20);
    notePaint.setStrokeWidth(2);
    canvas.drawLine(x0, y0, x0 + 500, y0, notePaint); // 绘制横轴
    canvas.drawLine(x0, y0, x0, y0 - 290, notePaint); // 绘制纵轴

    // 绘制横轴刻度和数字
    for (int i = 1; i <= 4; i++) {
        int step = i * 100;
        String n = String.valueOf(step);
        float x = x0 + step;
        canvas.drawLine(x, y0 - halfLine, x, y0 + halfLine, notePaint); // 刻度

        // 文字对齐
        textPaint.getTextBounds(n, 0, n.length(), textRect);
        canvas.drawText(n, x - textRect.width() / 2f, y0 + textRect.height() + halfLine, textPaint);
    }


    // 绘制纵轴刻度和数字
    for (int i = 1; i <= 2; i++) {
        int step = i * 100;
        String n = String.valueOf(step);
        float y = y0 - step;
        canvas.drawLine(x0 - halfLine, y, x0 + halfLine, y, notePaint); // 刻度

        // 文字对齐
        textPaint.getTextBounds(n, 0, n.length(), textRect);
        canvas.drawText(n, x0 - halfLine * 2 - textRect.width(), y + textRect.height() / 2f, textPaint);
    }

    // 绘制原点 0
    String origin = "0";
    textPaint.getTextBounds(origin, 0, origin.length(), textRect);
    canvas.drawText(origin, x0 - textRect.width(), y0 + textRect.height(), textPaint);
}
本站说明

一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~

📖AndroidTutorial 📚AndroidTutorial 🙋反馈问题 🔥最近更新 🍪投喂作者

Ads