Android基础之自定义view使文字居中对齐显示

本以为,这个挺简单的,但是没想到文字加上后,发现不居中。

设置了        mPaintTv.setTextAlign(Paint.Align.CENTER);发现只能文字左右居中,上下依然不是正中心。like this 
 
中间的红线是中心线,但是文字却不是跟中心对齐的,而是文字底部跟中心线平齐。

这显然不符合按钮的显示啊,查阅了一下资料,发现,自定义view在drawText时候,这个文字的对齐还真的是有个小坑。

 

上图是从网上找到的,但是里面有一个坑,后面会讲。 
**先解释下,drawText(String text,float x,float y,Paint paint) 
里面的x参数,在paint未设置setTextAlign 时,默认是从横坐标x点处开始绘制第一个字符串的字符。 
如果mPaintTv.setTextAlign(Paint.Align.CENTER);则是整个字符串的中心点的横坐标是x

里面的y参数永远都跟 字符串的Baseline对齐。**

这也就是为什么我们用矩形的中心点去绘制text的时候,文字却不在正中心,反而是有些向上偏移。 
like this:

所以绘制的时候我们要把文字偏移的那段距离算出来: 
那么坑就出来了 :【前方高能】 
通过Paint.FontMetrics fm = mPaintTv.getFontMetrics(); 可以获得字体属性类FontMetrics  
而 FontMetrics 里面有两个很重要的属性就是ascent   和 descent

他们表示的不仅仅是如下图的距离,如果你debug过,会发现他们还带有正负号, 
说实话,当时我感觉真是日了哈士奇了。后来我发现,这也是可以理解的。 
就如图所示,以baseline为x轴,向下是正方向,向上为负方向。 
所以ascent永远都是负值。

 

搞清楚了这一点,我们就可以大大方方的计算了。 
如果想要文字居中显示,肯定是以中心线(虚线)为x轴了,但是现在是以baseline为x轴,只需要计算出中心线和baseline之间的距离即可(中心线与baseline之间的距离 = 中心线到底部的距离 - descent)。

首先: 
中心线到底部的距离是 = 整个文字的高度 / 2 ;即(-ascent + descent)/2

中心线与baseline之间的距离 = (-ascent + descent)/ 2 - descent ;即 (-ascent-descent) / 2

然后,只需要在drawText时候将y参数向上提高 中心线与baseline之间的距离即可

 

canvas.drawText("bjjg",maxWidth/2,maxHeight/2 - (fm.descent - (-fm.ascent + fm.descent)/2),mPaintTv);1

 

全部代码如下:

 

/**
 * Created by FanHaiChao on 2017/4/12.
 * 自定义的带动画的view
 */
public class MyButtonView extends View {
    private Paint mPaintBg;
    private Paint mPaintTv;
    private RectF rect;
    private float radius;

    private int index = 0;
    private int maxIndex = 24;

    private boolean isDraw = false;//是否绘制完成:true--绘制完成;false--未绘制完成
    private boolean isTo0 = false;//true:变显示, false:变消失


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

    public MyButtonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();

    }


    public MyButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    private void initView() {

        mPaintBg = new Paint();
        mPaintBg.setAntiAlias(true);
        mPaintBg.setStyle(Paint.Style.FILL);
        mPaintBg.setColor(Color.RED);

        mPaintTv = new Paint();
        mPaintTv.setAntiAlias(true);
        mPaintTv.setStyle(Paint.Style.FILL);
        mPaintTv.setColor(Color.WHITE);
        mPaintTv.setTextSize(36);
        mPaintTv.setTextAlign(Paint.Align.CENTER);
    }


    //每一帧 onDraw一次  index变一次 ondraw一次
    //注意onDraw 方法 会在view所在activity可见时调用,也就是说 view 重新可见时 也会调用onDraw
    @Override
    protected void onDraw(Canvas canvas) {
        if (isDraw) {
            float maxWidth = getWidth();
            float maxHeight = getHeight();

            if (index <= (maxIndex / 2)) {//前一半时间画圆,后一半时间画圆角矩形
                canvas.drawCircle(maxWidth / 2, maxHeight / 2, radius, mPaintBg);
                radius = ((maxHeight / 2) / (maxIndex / 2)) * index;

            } else {
                if (maxWidth > maxHeight) {
                    radius = maxHeight / 2;
                } else {
                    radius = maxWidth / 2;
                }

                float wr = ((maxWidth / 2 - radius) / (maxIndex / 2)) * (index - maxIndex/2);

                //参数:左边距,上边距,右边距,下边距
                rect = new RectF(maxWidth / 2 - radius - wr, 0, maxWidth / 2 + radius + wr, 2 * radius);
                canvas.drawRoundRect(rect, 90, 90, mPaintBg);

                canvas.drawLine(0,maxHeight/2,maxWidth,maxHeight/2,mPaintTv);
                Paint.FontMetrics fm = mPaintTv.getFontMetrics();
                canvas.drawText("暴躁的码字猴",maxWidth/2,maxHeight/2 - (fm.descent - (-fm.ascent + fm.descent)/2),mPaintTv);
            }

            if (isTo0) {
                index--;
            } else {
                index++;
                index = index <= maxIndex ? index : maxIndex;
            }

            if (index <= maxIndex && index >= -1) {
                invalidate();
            } else {
                System.out.println(index);
            }

        }
    }

    public void startShow(boolean draw) {
        isDraw = draw;
        if (index == maxIndex){
            isTo0 = true;
            radius= 0;
        }else {
            isTo0 = false;
            radius= 0;
        }
        invalidate();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值