自定义view 关于绘制文字居中问题的理解

本文详细解析了在Android自定义View中实现文字在X轴和Y轴居中的技巧。通过使用Canvas.drawText()和Paint.FontMetrics,文章展示了如何精确计算文字的宽度和高度,以确保文字在视图中完美居中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
     * 绘制
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawText(text, 0 ,getHeight()/2 ,mPaint);
    }

 

当我们用如上方法绘制文字时,会常常发现文字并不是位于自定义view高度的中间,这是因为我们忽略了文字本身的高度。

 在X轴居中

 

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //拿到字符串的宽度
    float stringWidth = mPaint.measureText(text);
    float x =(getWidth()-stringWidth)/2;
    canvas.drawText(text, x ,getHeight()/2 ,mPaint);
}

 

利用measureText(String text)这个方法,很容易拿到要绘制文字的宽度,再根据(getWidth()-stringWidth)/2简单计算,就可以得到在X轴起始绘制坐标

在Y轴居中

想要在Y轴居中,就要确定出绘制文字baseline时的所在Y轴的坐标。在Android中,和文字高度相关的信息都存在FontMetrics对象中。。

FontMetricsPaint的一个静态内部类,源码如下:

/**
     * Class that describes the various metrics for a font at a given text size.
     * Remember, Y values increase going down, so those values will be positive,
     * and values that measure distances going up will be negative. This class
     * is returned by getFontMetrics().
     */
    public static class FontMetrics {
        /**
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    }

 

FontMetrics有五个float类型值:

  • leading 留给文字音标符号的距离

  • ascentbaseline线到最高的字母顶点到距离,负值

  • topbaseline线到字母最高点的距离加上ascent

  • descentbaseline线到字母最低点到距离

  • bottomtop类似,系统为一些极少数符号留下的空间。topbottom总会比ascentdescent大一点的就是这些少到忽略的特殊符号

baseline上为负,下为正。可以理解为文字坐标系中的x轴,baseline可以理解为文字的坐标系。文字的绘制是从baseline开始的

 那么如何确定文字的Y轴坐标?

 
 

由于文字绘制是从baseline开始,所以想要文字的正中心和DrawTextView的中心重合,baseline就不能和getHeight()/2重合,而且baseline要在getHeight()/2下方。
但要在下方多少?就是2号线和3号线之间的距离。

|ascent|=descent+ 2 * ( 2号线和3号线之间的距离 )

换一种方式思考:2号线和3号线之间的距离 = (|ascent| + desent) / 2 - desent,这样是不是更好理解

修改代码如下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //文字的x轴坐标
    float stringWidth = mPaint.measureText(text);
    float x = (getWidth() - stringWidth) / 2;
    //文字的y轴坐标
    Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
    float y = getHeight() / 2 + (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;
    canvas.drawText(text, x, y, mPaint);
}

 



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值