Android自定义View使用canvas绘制文字实现居中、自动换行

Android自定义View使用canvas绘制文字实现居中、自动换行

作者:CM 时间:2015-08-13 分类:Android 评论:0条 浏览:804

在自定义view中用到canvas绘制文字的时候常常会碰到要求文字居中或者自动换行的需求,接下来我就介绍一下我的实现方法。
首先绘制文字居中:
绘制文字时可以通过Paint的getFontMetrics()方法得到文字度量相关信息如下图:
20130827162047703
上图所示的top、bottom、ascent、descent都是根据Paint的getFontMetrics()得到的FontMetrics取到的。
baseline是绘制文字Y坐标的基准点,也就是Y坐标的0点位置,向上为负,向下为正。所以descent是一个正值而ascent是一个负值。所以文字的真实高度是descent-ascent。
看一下绘制单行文字居中代码

Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(30);
/**
 * 设置绘制文字时起始点X坐标的位置
 * CENTER:以文字的宽度的中心点为起始点向两边绘制
 * LEFT:以文字左边为起始点向右边开始绘制
 * RIGHT:以文字宽度的右边为起始点向左边绘制
 */
textPaint.setTextAlign(Paint.Align.CENTER);

//获取文字度量信息
Paint.FontMetrics fm = textPaint.getFontMetrics();
float textHeight = fm.descent-fm.ascent;

//绘制文字的矩形框范围
RectF rectF = new RectF(100,100,500,100+textHeight);
Paint paint = new Paint();
paint.setColor(Color.YELLOW);

canvas.drawRect(rectF, paint);
canvas.drawText("Hello gafbcj World!", rectF.left + rectF.width() / 2, rectF.bottom-fm.descent, textPaint);

看一下显示效果:
20150813151834
OK,文字居中的效果搞定了.下面看看自动换行的实现。
用canvas直接drawText是不能自动换行的,需要用到StaticLayout来实现.

TextPaint textPaint = new TextPaint();
textPaint.setColor(Color.BLUE);
textPaint.setTextSize(30);

Rect rect = new Rect(100,100,300,400);

String text = "这是一串需要进行换行显示的文字。";

//文字自动换行
StaticLayout layout = new StaticLayout(text, textPaint, rect.width(), Layout.Alignment.ALIGN_NORMAL, 1.0F, 0.0F,true);
canvas.save();
textPaint.setTextAlign(Paint.Align.LEFT);
//文字的位置
canvas.translate(rect.left , rect.top);
layout.draw(canvas);
canvas.restore();

看一下效果:
20150813154153
自动换行实现了,怎么实现文字在显示区域内居中呢?需要计算文字的高度然后设置绘制文字的起始Y坐标.这就需要对文字进行处理,计算出文字显示的行数

/**
 * 将文字拆分成每一行放到Vector里
 */
public Vector getTextLinesVector(TextPaint paint, String content, float maxHeight,
                                         float maxWidth) {
    Vector mString = new Vector<>();
    int mRealLine = 0;// 字符串真实的行数
    char ch;
    int w = 0;
    int istart = 0;
    float mFontHeight = getFontHeight(paint);
    int mMaxLinesNum = (int)(maxHeight / mFontHeight);//显示的最大行数
    int count = content.length();
    for (int i = 0; i < count; i++) {
        ch = content.charAt(i);
        float[] widths = new float[1];
        String str = String.valueOf(ch);
        paint.getTextWidths(str, widths);
        if (ch == '\n') {
            mRealLine++;// 真实的行数加一
            mString.addElement(content.substring(istart, i));
            istart = i + 1;
            w = 0;
        } else {
            w += (int) Math.ceil(widths[0]);
            if (w > maxWidth) {
                mRealLine++;// 真实的行数加一
                mString.addElement(content.substring(istart, i));
                istart = i;
                i--;
                w = 0;
            } else {
                if (i == count - 1) {
                    mRealLine++;// 真实的行数加一
                    mString.addElement(content.substring(istart, count));
                }
            }
        }
        //当真实行数大于显示的最大行数时跳出循环
        if(mRealLine == mMaxLinesNum){
            break;
        }
    }

    return mString;
}

/**
 *得到文字的高度
 */
private float getFontHeight(TextPaint paint) {
    Paint.FontMetrics fm = paint.getFontMetrics();// 得到系统默认字体属性
    return fm.bottom - fm.top;
}

大家可能发现这里计算文字高度用的是bottom-top而不是上面用的descent-ascent,这是因为descent-ascent是文字的真实高度,而bottom-top是文字显示区域的高度,绘制的时候文字上下是有一定的间距的.
获得拆分每一行以后的文字再用上面的换行的方法进行绘制,调整绘制时的起始位置

private void drawLinesText(Canvas canvas) {
    TextPaint textPaint = new TextPaint();
    textPaint.setColor(Color.BLUE);
    textPaint.setTextSize(30);

    Rect rect = new Rect(100,100,300,400);

    String text = "这是一串需要进行换行显示的文字。";

    //获得自动换行后的文字
    Vector vector = getTextLinesVector(textPaint, text, rect.height(), rect.width());
    text = vectorToString(vector);
    //文字自动换行
    StaticLayout layout = new StaticLayout(text,textPaint, rect.width(), Layout.Alignment.ALIGN_NORMAL, 1.0F, 0.0F,true);
    canvas.save();
    textPaint.setTextAlign(Paint.Align.CENTER);
    //文字的位置
    canvas.translate(rect.left + rect.width()/2, rect.top+ (rect.height()  - getFontHeight(textPaint)*vector.size())/2);
    layout.draw(canvas);
    canvas.restore();
}

private String vectorToString(Vector strs) {
    StringBuffer ss = new StringBuffer();
    for (String s : strs) {
        ss.append(s+"\n");
    }
    return ss.toString();
}

最后的效果
20150813160158

相关推荐
更多

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>