2018-06-15
首先我們看看怎樣在Android中繪制出文字 以及與可以方便我們理解基線的其它線條
如何在android的View控件中繪制文字:
重寫(xiě)View的onDraw方法 使用其Canvas類(lèi)的方法 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是手機(jī)屏幕的寬和高
@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);
}
參數(shù)初始化方法
private void init(){
texPaint = new Paint();//文字畫(huà)筆
texPaint.setTextSize(300);
texPaint.setColor(Color.BLACK);
texPaint.setTextAlign(Paint.Align.CENTER);
texPaint.setTypeface(Typeface.DEFAULT_BOLD);
centerLineP = new Paint();//屏幕中線畫(huà)筆
centerLineP.setStrokeWidth(15);
centerLineP.setColor(Color.RED);
topLineP = new Paint();//文字頂線畫(huà)筆
topLineP.setStrokeWidth(15);
topLineP.setColor(Color.GREEN);
bottomLineP = new Paint();//文字底線畫(huà)筆
bottomLineP.setStrokeWidth(15);
bottomLineP.setColor(Color.YELLOW);
texCenterLineP = new Paint();//文字中線畫(huà)筆
texCenterLineP.setStrokeWidth(5);
texCenterLineP.setColor(Color.BLACK);
halfLineP = new Paint();//分隔線畫(huà)筆
halfLineP.setStrokeWidth(15);
halfLineP.setColor(Color.MAGENTA);
Paint.FontMetricsInt fontMetricsInt = texPaint.getFontMetricsInt();
top = fontMetricsInt.top;
bottom = fontMetricsInt.bottom;
baseLine = (bottom - top) / 2 - bottom;//文字基線
}
最終獲取的效果如下:
現(xiàn)在我們來(lái)談?wù)勊^的文字“基線”是什么
文字的“基線”就如同是我們的英語(yǔ)寫(xiě)字用的“四線本” 實(shí)際上我們正式寫(xiě)字的時(shí)候?yàn)榱苏麧?都是有一條線的
所以我們可以發(fā)現(xiàn)在“效果圖”上 文字和上述何等相似:a e r等單字都排布在基線上 而j g卻超出了基線 但是g這個(gè)字在上半部分也是老實(shí)地排布在基線上 這和我們寫(xiě)英文字時(shí)的習(xí)慣是一模一樣的
android文字的繪制也以使用了同樣的方法使繪制出的文字保證整齊劃一地排布:給文字定了一條基準(zhǔn)線 而我們上述通過(guò)Paint.FontMetricsInt 獲取的top和bottom值就與基線有關(guān)
圖片來(lái)源:https://blog.csdn.net/hailuoli/article/details/78558594
在我的手機(jī)上 top 為 - 317 bottom 為 82 計(jì)算出基線(偏移)為117
這里的top和bottom的值 實(shí)際是基于基線而得 可理解為 以文字基線為準(zhǔn) 向上平移317像素為繪制區(qū)域的頂 向下平移82像素為繪制區(qū)域的底(基線向上為負(fù) 向下為正)
已知基線與繪制區(qū)頂相距317 與底相距82 得繪制區(qū)高度 bottom - top:82 - (-317) = 399
繪制區(qū)中線高度為(bottom - top)/ 2 : 399 / 2 = 199 (int)
繪制區(qū)中線高度等價(jià)于 中線與繪制區(qū)底 之間的距離 這個(gè)距離減去 基線與繪制區(qū)底 之間的距離 就是中線與基線之間的距離 (bottom - top) / 2 - bottom : 199 - 82 = 117
那這個(gè)值和我們?cè)赼ndroid中繪制文字有什么關(guān)系呢卿操?
關(guān)鍵在于 我們?cè)谏鲜龃a中 drawText傳入的y值是屏幕的高 / 2 因?yàn)槲覀兿M淖挚梢猿霈F(xiàn)在屏幕的中間 但是事與愿違 我們的文字很明顯沒(méi)有出居中于屏幕
--因?yàn)?drawText中傳入的Y的實(shí)際意義是文字的基線所在的位置--
我們將文字的基線放在了屏幕中間 文字在繪制出來(lái)時(shí)當(dāng)然不會(huì)居中于屏幕 -- 我們應(yīng)該將文字的中線放在屏幕的中間 這樣文字在繪制出來(lái)時(shí)就可以居中了
因?yàn)橐婚_(kāi)始我們傳的y實(shí)際是文字基線將要所在的位置 現(xiàn)在我們想傳入的y應(yīng)該是中線的位置 上面我們得到中線和基線的距離是117 所以應(yīng)該以之前的y + 117(baseLine 基線偏移值):
canvas.drawText("jaeger",measureWidth / 2,measureHeight / 2 + baseLine,texPaint);
當(dāng)然 明白了基線的作用和使用方法 那我們已應(yīng)該可以處理這種問(wèn)題:
canvas.drawText("jaeger",measureWidth / 2,0 + baseLine,texPaint);//文字
經(jīng)常繪制文字發(fā)現(xiàn)考慮基線偏移是很常見(jiàn)的問(wèn)題
這時(shí)應(yīng)該這樣:
canvas.drawText("jaeger",measureWidth / 2,-top,texPaint);//文字
文字顯示完整了
當(dāng)然 文字繪制的參考線不只有top 和 bottom跟匆,還有ascent;descent;leading 參見(jiàn)“示例”圖