1. 落筆緣由
由于要實(shí)現(xiàn)類似注冊表單一樣瘪吏,文字作用兩端對齊的效果如下圖1铃彰,所以才有下面的內(nèi)容盏檐。
在canvas中歇式,調(diào)用drawText繪畫文字的時候,希望能夠在垂直方向居中畫出文字胡野。所以需要測量出要繪畫的文字的高材失。但具體來說,也不是獲取文字的高硫豆,因?yàn)槿绻怪本又挟嫵鑫淖至蓿捅仨毮玫轿淖值腷aseline,于是在網(wǎng)上搜索熊响,找到了一篇關(guān)于獲取baseline的文章(文章鏈接在本文底部列出)旨别,感覺就是我想要的,但是基于要懷疑一切的態(tài)度汗茄,不能你說是什么就是什么的秸弛,實(shí)踐才是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),所以下面我們來驗(yàn)證一下幾個觀點(diǎn)洪碳。
(1) 字體的5個位置是由使用的字體和字號決定的
首先可以明確递览,5個位置分別是top,ascent瞳腌,baseline绞铃,descent,bottom嫂侍。這五個位置受字號的大小影響是毋庸置疑的儿捧,這里不再討論冷离。這里驗(yàn)證了一下字體對五個位置的影響。字號默認(rèn)是16纯命,字體分別是系統(tǒng)默認(rèn)西剥,行書,小篆亿汞,方正姚體:
這5個位置分別用5條不同顏色的橫線條展示
- top:淺灰色
- ascent:黃色
- baseline:紅色
- descent:藍(lán)色
- bottom:綠色
1)代碼展示
private void init()
{
bodyLayout = new LinearLayout(this);
if (bodyLayout != null)
{
llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
if (llParams!=null)
{
bodyLayout.setLayoutParams(llParams);
}
bodyLayout.setOrientation(LinearLayout.VERTICAL);
bodyLayout.setBackgroundColor(Color.WHITE);
//系統(tǒng)默認(rèn)字體
MeasureText measureText = new MeasureText(this);
if (measureText!=null)
{
llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
Util.dip2px(this, 200));
if (llParams!=null)
{
measureText.setLayoutParams(llParams);
}
bodyLayout.addView(measureText);
}
//行書
MeasureText measureText2 = new MeasureText(this);
if (measureText2!=null)
{
llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
Util.dip2px(this, 200));
if (llParams!=null)
{
measureText2.setLayoutParams(llParams);
}
Typeface face = Typeface.createFromAsset (getAssets() , "fonts/xs.ttf" );
measureText2.setFace(face);
bodyLayout.addView(measureText2);
}
//小篆
MeasureText measureText3 = new MeasureText(this);
if (measureText3!=null)
{
llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
Util.dip2px(this, 200));
if (llParams!=null)
{
measureText3.setLayoutParams(llParams);
}
Typeface face = Typeface.createFromAsset (getAssets() , "fonts/fzxz.TTF" );
measureText3.setFace(face);
bodyLayout.addView(measureText3);
}
//方正姚體
MeasureText measureText4 = new MeasureText(this);
if (measureText4!=null)
{
llParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
Util.dip2px(this, 200));
if (llParams!=null)
{
measureText4.setLayoutParams(llParams);
}
Typeface face = Typeface.createFromAsset (getAssets() , "fonts/fzyt.TTF" );
measureText4.setFace(face);
bodyLayout.addView(measureText4);
}
}
}
2)效果演示
3)結(jié)果
從效果看,字體對top吴裤,ascent旧找,baseline,descent麦牺,bottom的位置影響并不明顯钮蛛。
(2)以baseline為基準(zhǔn),向上為負(fù)剖膳,向下為正魏颓。ascent為負(fù)數(shù),descent為正數(shù)吱晒。
通過Log打印的日志可以得出結(jié)果
結(jié)果:以baseline為基準(zhǔn)線甸饱,向上為負(fù),向下為正是正確的仑濒。
(3)如果嘗試將兩個TextView上下排列叹话,沒有margin和padding,兩個TextView文字之間依然有空隙墩瞳。首先我們需要設(shè)置includeFontPadding為false驼壶!但是依然有空隙,這時的空隙就是由top與ascent之間的空隙和bottom與descent直接的空隙造成的了矗烛。這個就不用例子驗(yàn)證了辅柴,不然怎么解釋這個空隙的存在。
(4)baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent
這個不是驗(yàn)證了瞭吃,說了那么多也就是為了如何在垂直方向居中繪制文字,關(guān)鍵在于獲取baseline位置涣旨。Canvas中的drawText中繪制文字的基準(zhǔn)線是baseline歪架。
baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent
使得ascent到View的是上邊距與descent到View下邊距距離一致即可,此段距離加上ascent的絕對值(-ascent)即為baseline的位置霹陡。
2. 總結(jié)
在Canvas中使用drawText繪制垂直居中文字的關(guān)鍵在于求出baseline的位置和蚪。獲取位置的公式:
baseline = (mHeight - (mFontMetricsInt.descent -
mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent
即baseline = (mHeight - mFontMetricsInt.ascent -mFontMetricsInt.descent)
/ 2
3. 源碼地址
https://github.com/lgygg/MeasureHeight