Android文字绘制 -- 怎样理解“基线”

2018-06-15

首先我们看看怎样在Android中绘制出文字 以及与可以方便我们理解基线的其它线条
如何在android的View控件中绘制文字:
重写View的onDraw方法 使用其Canvas类的方法 canvas.drawText();

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawText("jaeger",measureWidth / 2,measureHeight / 2,texPaint);//文字

    canvas.drawLine(0,measureHeight / 2,measureWidth,measureHeight / 2,centerLineP);//屏幕中线

    canvas.drawLine(0,measureHeight / 2 + (top + bottom) / 2,measureWidth,measureHeight / 2 + (top + bottom) / 2,texCenterLineP);//文字中线

    canvas.drawLine(0,measureHeight / 2 + top,measureWidth,measureHeight / 2 + top,topLineP);//文字顶线

    canvas.drawLine(0,measureHeight / 2 + bottom,measureWidth,measureHeight / 2 + bottom,bottomLineP);//文字顶线

    canvas.drawLine(0,measureHeight / 2 - 400,measureWidth,measureHeight / 2 - 400,halfLineP);//屏幕上分隔线
    canvas.drawLine(0,measureHeight / 2 + 400,measureWidth,measureHeight / 2 + 400,halfLineP);//屏幕下分隔线
}

其中measureWidth与measureHeight是手机屏幕的宽和高

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY)
        measureWidth = MeasureSpec.getSize(widthMeasureSpec);
    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY)
        measureHeight = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(measureWidth,measureHeight);
}

参数初始化方法

private void init(){
    texPaint = new Paint();//文字画笔
    texPaint.setTextSize(300);
    texPaint.setColor(Color.BLACK);
    texPaint.setTextAlign(Paint.Align.CENTER);
    texPaint.setTypeface(Typeface.DEFAULT_BOLD);

    centerLineP = new Paint();//屏幕中线画笔
    centerLineP.setStrokeWidth(15);
    centerLineP.setColor(Color.RED);

    topLineP = new Paint();//文字顶线画笔
    topLineP.setStrokeWidth(15);
    topLineP.setColor(Color.GREEN);

    bottomLineP = new Paint();//文字底线画笔
    bottomLineP.setStrokeWidth(15);
    bottomLineP.setColor(Color.YELLOW);

    texCenterLineP = new Paint();//文字中线画笔
    texCenterLineP.setStrokeWidth(5);
    texCenterLineP.setColor(Color.BLACK);

    halfLineP = new Paint();//分隔线画笔
    halfLineP.setStrokeWidth(15);
    halfLineP.setColor(Color.MAGENTA);

    Paint.FontMetricsInt fontMetricsInt = texPaint.getFontMetricsInt();
    top = fontMetricsInt.top;
    bottom = fontMetricsInt.bottom;
    baseLine = (bottom - top) / 2 - bottom;//文字基线
}

最终获取的效果如下:


效果图

现在我们来谈谈所谓的文字“基线”是什么
文字的“基线”就如同是我们的英语写字用的“四线本” 实际上我们正式写字的时候为了整洁 都是有一条线的

文字

所以我们可以发现在“效果图”上 文字和上述何等相似:a e r等单字都排布在基线上 而j g却超出了基线 但是g这个字在上半部分也是老实地排布在基线上 这和我们写英文字时的习惯是一模一样的

android文字的绘制也以使用了同样的方法使绘制出的文字保证整齐划一地排布:给文字定了一条基准线 而我们上述通过Paint.FontMetricsInt 获取的top和bottom值就与基线有关

示例

图片来源:https://blog.csdn.net/hailuoli/article/details/78558594

在我的手机上 top 为 - 317 bottom 为 82 计算出基线(偏移)为117
这里的top和bottom的值 实际是基于基线而得 可理解为 以文字基线为准 向上平移317像素为绘制区域的顶 向下平移82像素为绘制区域的底(基线向上为负 向下为正)

已知基线与绘制区顶相距317 与底相距82 得绘制区高度 bottom - top:82 - (-317) = 399
绘制区中线高度为(bottom - top)/ 2 : 399 / 2 = 199 (int)
绘制区中线高度等价于 中线与绘制区底 之间的距离 这个距离减去 基线与绘制区底 之间的距离 就是中线与基线之间的距离 (bottom - top) / 2 - bottom : 199 - 82 = 117

那这个值和我们在android中绘制文字有什么关系呢?
关键在于 我们在上述代码中 drawText传入的y值是屏幕的高 / 2 因为我们希望文字可以出现在屏幕的中间 但是事与愿违 我们的文字很明显没有出居中于屏幕

--因为 drawText中传入的Y的实际意义是文字的基线所在的位置--

我们将文字的基线放在了屏幕中间 文字在绘制出来时当然不会居中于屏幕 -- 我们应该将文字的中线放在屏幕的中间 这样文字在绘制出来时就可以居中了

因为一开始我们传的y实际是文字基线将要所在的位置 现在我们想传入的y应该是中线的位置 上面我们得到中线和基线的距离是117 所以应该以之前的y + 117(baseLine 基线偏移值):

    canvas.drawText("jaeger",measureWidth / 2,measureHeight / 2 + baseLine,texPaint);
效果

当然 明白了基线的作用和使用方法 那我们已应该可以处理这种问题:

    canvas.drawText("jaeger",measureWidth / 2,0 + baseLine,texPaint);//文字
不完全显示

经常绘制文字发现考虑基线偏移是很常见的问题
这时应该这样:

    canvas.drawText("jaeger",measureWidth / 2,-top,texPaint);//文字

文字显示完整了


完全显示

当然 文字绘制的参考线不只有top 和 bottom,还有ascent;descent;leading 参见“示例”图

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