Android自定义View五(绘制文本大小、多行多列居中)

一、绘制文本

在Canvas中绘制文本,使用前面文章的坐标系

1、drawText的几种方法

public void drawText (String text, float x, float y, Paint paint)
public void drawText (String text, int start, int end, float x, float y, Paint paint)
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)
public void drawText (char[] text, int index, int count, float x, float y, Paint paint)

public void drawText (String text, float x, float y, Paint paint)
x 、 y轴表示绘制文本左下角到坐标

        mPaint.setColor(Color.RED);
        mPaint.setTextSize(50);
        String string="HeDan";
        canvas.drawText(string,0,0,mPaint);
xyText.png

public void drawText (String text, int start, int end, float x, float y, Paint paint)
绘制一部分Text,start表示从第几个字符开始,end表示第几个字符之前结束

//public void drawText (String text, int start, int end, float x, float y, Paint paint)
        canvas.drawText(string,0,3,0,0,mPaint);
starttext.png

public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)使用CharSequence绘制,方法,效果同上
public void drawText (char[] text, int index, int count, float x, float y, Paint paint)使用字符数组绘制,方法,效果同上

2、drawPosText

给文本中到每个字符都设定一个坐标,不推荐使用

3、drawTextOnPath

通过Path进行文本绘制,path是一个比较重要且有趣的东西,在之后涉及知识中会进行分析。

Path path = new Path();
path.lineTo(0,200);
canvas.drawTextOnPath(string,path,100,100,mPaint);

这里简单写一个,path为一条从原点到(0,200)的直线,水平偏移量、垂直偏移量都设置为100,效果如下:

pathtext.png

二、文本居中

1、单行文本居中

a、 public void getTextBounds(String text, int start, int end, Rect bounds)

通过Rect获取文本宽度和高度,方法如下

Rect rect = new Rect();
mPaint.getTextBounds(string,0,string.length(),rect);
 int width = rect.width();//文本宽度
int height = rect.height();//文本高度
b、getFontMetrics(),getFontMetricsInt()用于返回字符串的测量,而两个方法的区别就是返回值得类型。返回值一共五个属性:
  • Top: baseline到文本顶部的最大的距离
  • Ascent:baseline到文本顶部到推荐距离
  • Descent:baseline到文本底部到推荐距离
  • Bottom:baseline到文本底部到最大距离
  • Leading:两行文本之间推荐到额外距离,一般为0(推荐不考虑)
String-Center.png

在Android的坐标系中,向下为Y轴正方向,向上为Y轴负方向,所部baseling之上到Top与Ascent都是负数,而baselin之下到Descent、Bottom都是正数。如果要让字符串在垂直方向上居中,则需要在纵坐标上增加Asecent绝对值与descent的差。

 Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
 float textHeight=(-fontMetrics.ascent-fontMetrics.descent)/2;
 canvas.drawText(string,0,textHeight,mPaint);
ycentent.png
c、setTextAlign可以设置画笔绘制文本到对齐方式,选择center即可完成文本到水平居中
 Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
 float textHeight=(-fontMetrics.ascent-fontMetrics.descent)/2;
 mPaint.setTextAlign(Paint.Align.CENTER);
  canvas.drawText(string,0,textHeight,mPaint);
xcentent.png

d、measureText可以测量文本的宽度,即横向长度,这样也可以来完成居中设置,但在这之前,需要恢复文本对齐方式至默认设置(居左)。

     Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
     float textHeight=(-fontMetrics.ascent-fontMetrics.descent)/2;
    float textWidth = mPaint.measureText(string);
     canvas.drawText(string,-textWidth/2,textHeight,mPaint);

效果同上C。

2、多行文本居中

有设定好的字符串数组,画笔,画布,坐标点

  • 1、drawText每次只能绘制一行,通过for循环
  • 2、字符串数组大于1时,每个字符到高度应该为-top+bottom,总高度为length*(-top+bottom)
  • 3、偏移量就等于length*(-top+bottom)/2-bottom
  • 4、如果顺序向上(Y负方向)排列到话,那么第i个字符串到高度就是-(length-i-1)*(-top+bottom)
  • 5、每个字符串高度减去偏移量,就应该是每个字符串到baseline的y坐标
    详细代码
 private void textCenter(String [] strings, Paint paint, Canvas canvas, Point point,Paint.Align aligin){
        paint.setTextAlign(aligin);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float top=fontMetrics.top;
        float bottom=fontMetrics.bottom;
        int length=strings.length;
        float total=(length-1)*(-top+bottom)+(-fontMetrics.ascent+fontMetrics.descent);
        float offset=total/2-bottom;
        for(int i=0;i<length;i++){
            float yAxis=-(length-i-1)*(-top+bottom)+offset;
            canvas.drawText(strings[i]+"",point.x,point.y+yAxis,paint);
        }
    }

偏移量取值的变化,是因为在字符串的首尾两个字符串,需要把top改成ascent,bottom改成descent。通过设置画笔来完成横向的居中,居左,居右。

使用代码

String[] striings={"HeDan","是","一","个","好","学","生"};
//String[] striings={"床前明月光,","疑是地上霜。","举头望明月,","低头思故乡。"};
Point point=new Point(0,0);
//textCenter(striings,mPaint,canvas,point, Paint.Align.CENTER);
textCenter(striings,mPaint,canvas,point, Paint.Align.LEFT);
ytext.png
ytext1.png
ytext2.png

3、多列文本

  • 1、一个字符串数组
  • 2、每个字符数组中获取最宽到字符宽度我字符数组的宽度
  • 3、计算数组x坐标,再掉用之前多行文本居中到代码
居右详细代码
  private void textCenter(char[]  strings, Paint paint, Canvas canvas, Point point,Paint.Align aligin){
        paint.setTextAlign(aligin);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float top=fontMetrics.top;
        float bottom=fontMetrics.bottom;
        int length=strings.length;
        float total=(length-1)*(-top+bottom)+(-fontMetrics.ascent+fontMetrics.descent);
        float offset=total/2-bottom;
        for(int i=0;i<length;i++){
            float yAxis=-(length-i-1)*(-top+bottom)+offset;
            canvas.drawText(strings[i]+"",point.x,point.y+yAxis,paint);
        }
    }

    private void rowTextRight(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            point.x=point.x-(int)total;
            textCenter(chars,paint,canvas,point, Paint.Align.RIGHT);
            point.x = point.x + (int) total;
            total = total+len;
        }
    }

使用代码

     String[] striings={"鹅,鹅,鹅,","曲项向天歌,","白毛浮绿水,","红掌拨清波,"};
        Point point=new Point(0,0);
        rowTextRight(striings,mPaint,canvas,point);
ytext3.png
居左详细代码
  private void rowTextLeft(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            point.x=point.x+(int)total;
            textCenter(chars,paint,canvas,point, Paint.Align.LEFT);
            point.x = point.x - (int) total;
            total = total+len;
        }
    }
ytext.png
居中详细代码
  private void rowTextCenter(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            total = total+len;
        }

        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            if(j==0){
                point.x=(int)-(total-len)/2;
            }
            textCenter(chars,paint,canvas,point, Paint.Align.CENTER);
            point.x=point.x+(int)len;
        }
    }

```
ytext.png

4、文本自动换行居中

自动换行在Android 自定义View 一(初体验onDraw(),自定义属性,onMeasue()方法,测量换行)这里在介绍一个系统到方法:
StaticLayout,可以设置宽度,当前行文本超过此宽度后,进行自动换行,提供提供ALIGN_CENTER(居中)、ALIGN_NORMAL(标准)、ALIGN_OPPOSITE(与标准相反)三种对齐方式
详细代码:

  private void textCenter(String string, TextPaint textPaint, Canvas canvas, Point point, int width, Layout.Alignment align,float spacingmult,float spacingadd,boolean includepad){
        StaticLayout staticLayout = new StaticLayout(string,textPaint,width, align,spacingmult,spacingadd,includepad);
        canvas.save();
        canvas.translate(-staticLayout.getWidth()/2+point.x,-staticLayout.getHeight()/2+point.y);
        staticLayout.draw(canvas);
        canvas.restore();

    }

使用方法

  String mString="HeDan是一个好学生";
        TextPaint tp = new TextPaint();
        tp.setColor(Color.BLUE);
        tp.setStyle(Paint.Style.FILL);
        Point point=new Point(0,0);
        tp.setTextSize(50);
        textCenter(mString,tp,canvas,point,200,Layout.Alignment.ALIGN_CENTER,1.5f,0,false);
ytext.png

下面贴出学习源码:

public class MultipleText extends View {
    private Paint mPaint;
    private float pWidth;
    private float pHeight;
    private int mWidth;
    private int mHeight;

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

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

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

    /**
     * 初始化画笔
     */
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);//设置画笔填充
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setColor(Color.parseColor("#52adff"));//设置画笔颜色

    }

    ;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);

        mPaint.setStrokeWidth(10);//设置原点宽度
        canvas.drawPoint(0, 0, mPaint);//绘制原点
        canvas.drawPoints(new float[]{pWidth, 0, 0, pHeight, -pWidth, 0, 0, -pHeight}, mPaint);//绘制边缘点*/

        mPaint.setStrokeWidth(1);//重新设置画笔到宽度
        canvas.drawLine(-pWidth, 0, pWidth, 0, mPaint);//绘制X轴
        canvas.drawLine(0, -pHeight, 0, pHeight, mPaint);//绘制Y轴

        mPaint.setStrokeWidth(3);//设置箭头宽度
        canvas.drawLines(new float[]{pWidth, 0, pWidth * 0.95f, -pWidth * 0.05f, pWidth, 0, pWidth * 0.95f, pWidth * 0.05f}, mPaint);//X轴箭头
        canvas.drawLines(new float[]{0, pHeight, -pHeight * 0.05f, pHeight * 0.95f, 0, pHeight, pHeight * 0.05f, pHeight * 0.95f}, mPaint);//Y轴箭头

        mPaint.setColor(Color.RED);
        mPaint.setTextSize(50);
        String string="HeDan";
        //public void drawText (String text, float x, float y, Paint paint)
        //canvas.drawText(string,0,0,mPaint);
        //public void drawText (String text, int start, int end, float x, float y, Paint paint)
       // canvas.drawText(string,0,3,0,0,mPaint);
      /*  Path path=new Path();
        path.lineTo(0,200);
        canvas.drawTextOnPath(string,path,100,100,mPaint);
        Rect rect = new Rect();
        mPaint.getTextBounds(string,0,string.length(),rect);
        int width = rect.width();//文本宽度
        int height = rect.height();//文本高度*/
       /* Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        float textHeight=(-fontMetrics.ascent-fontMetrics.descent)/2;
        float textWidth = mPaint.measureText(string);
        canvas.drawText(string,-textWidth/2,textHeight,mPaint);*/

  /*      String[] striings={"鹅,鹅,鹅,","曲项向天歌,","白毛浮绿水,","红掌拨清波,"};
        Point point=new Point(0,0);
      textCenter(striings,mPaint,canvas,point, Paint.Align.LEFT);
        rowTextCenter(striings,mPaint,canvas,point);*/

        String mString="HeDan是一个好学生";
        TextPaint tp = new TextPaint();
        tp.setColor(Color.BLUE);
        tp.setStyle(Paint.Style.FILL);
        Point point=new Point(0,0);
        tp.setTextSize(50);
        textCenter(mString,tp,canvas,point,200,Layout.Alignment.ALIGN_CENTER,1.5f,0,false);



    }
    private void textCenter(String [] strings, Paint paint, Canvas canvas, Point point,Paint.Align aligin){
        paint.setTextAlign(aligin);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float top=fontMetrics.top;
        float bottom=fontMetrics.bottom;
        int length=strings.length;
        float total=(length-1)*(-top+bottom)+(-fontMetrics.ascent+fontMetrics.descent);
        float offset=total/2-bottom;
        for(int i=0;i<length;i++){
            float yAxis=-(length-i-1)*(-top+bottom)+offset;
            canvas.drawText(strings[i],point.x,point.y+yAxis,paint);
        }
    }

    private void textCenter(char[]  strings, Paint paint, Canvas canvas, Point point,Paint.Align aligin){
        paint.setTextAlign(aligin);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float top=fontMetrics.top;
        float bottom=fontMetrics.bottom;
        int length=strings.length;
        float total=(length-1)*(-top+bottom)+(-fontMetrics.ascent+fontMetrics.descent);
        float offset=total/2-bottom;
        for(int i=0;i<length;i++){
            float yAxis=-(length-i-1)*(-top+bottom)+offset;
            canvas.drawText(strings[i]+"",point.x,point.y+yAxis,paint);
        }
    }

    private void rowTextRight(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            point.x=point.x-(int)total;
            textCenter(chars,paint,canvas,point, Paint.Align.RIGHT);
            point.x = point.x + (int) total;
            total = total+len;
        }
    }

    private void rowTextLeft(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            point.x=point.x+(int)total;
            textCenter(chars,paint,canvas,point, Paint.Align.LEFT);
            point.x = point.x - (int) total;
            total = total+len;
        }
    }
    private void rowTextCenter(String[] strings,Paint paint,Canvas canvas,Point point){
        int length = strings.length;
        float len ,newLen;
        float total=0;
        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            total = total+len;
        }

        for(int j=0;j<length;j++){
            char[] chars = strings[j].toCharArray();
            len=paint.measureText(chars[0]+"");
            for (int i=1; i<chars.length; i++){
                newLen = mPaint.measureText(chars[i]+"");
                len = Math.max(newLen,len);
            }
            if(j==0){
                point.x=(int)-(total-len)/2;
            }
            textCenter(chars,paint,canvas,point, Paint.Align.CENTER);
            point.x=point.x+(int)len;
        }
    }

    private void textCenter(String string, TextPaint textPaint, Canvas canvas, Point point, int width, Layout.Alignment align,float spacingmult,float spacingadd,boolean includepad){
        StaticLayout staticLayout = new StaticLayout(string,textPaint,width, align,spacingmult,spacingadd,includepad);
        canvas.save();
        canvas.translate(-staticLayout.getWidth()/2+point.x,-staticLayout.getHeight()/2+point.y);
        staticLayout.draw(canvas);
        canvas.restore();

    }




    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        pWidth = mWidth / 2 * 0.8f;//X轴边缘原点到原点到距离
        pHeight = mHeight / 2 * 0.8f;//Y轴边缘原点到原点到距离
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容