使用Paint實(shí)現(xiàn)的文字繪制(文字的基線(xiàn))
請(qǐng)尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處【tianyl】的博客
關(guān)于的Android之玩轉(zhuǎn)View目錄
前言
上篇文章介紹了一些使用Paint和Shader結(jié)合實(shí)現(xiàn)的一些特效熄云,不過(guò)都是一些圖像繪制方面的舶沛,當(dāng)然匀借,Paint除了能夠進(jìn)行圖像繪制之外误墓,還有另外一個(gè)功能偎漫,就是文字的繪制
當(dāng)然,在學(xué)習(xí)Paint繪制文字之前尔邓,最好能夠熟悉一些Paint繪制文字的api這是Paint繪制文字的常用api說(shuō)明
1 文字的基線(xiàn)
說(shuō)到文字繪制晾剖,先從一個(gè)api說(shuō)起
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
這是一個(gè)常用的繪制文字的辦法,可能有朋友會(huì)遇到梯嗽,在使用這個(gè)方法繪制文字的時(shí)候钞瀑,文字的位置經(jīng)常不對(duì),不是高了慷荔,就是低了雕什,這就是由于這個(gè)api中的x和y造成的
看圖說(shuō)明
在我們繪制文字的時(shí)候,通常有上圖中的六條線(xiàn)显晶,分別是
- top:頂點(diǎn)線(xiàn)
- ascent:建議頂點(diǎn)線(xiàn)
- center:中心線(xiàn)
- baseline:基線(xiàn)
- descent:建議底部線(xiàn)
- bottom:底部線(xiàn)
這六條線(xiàn)分別起什么作用呢贷岸?
- 首先是top和bottom,這兩條線(xiàn)很好理解磷雇,它分別是頂端和底端偿警,繪制文字時(shí)肯定不會(huì)超過(guò)這兩條線(xiàn)
- 然后是ascent和descent,這兩條線(xiàn)是建議的頂點(diǎn)線(xiàn)和建議底端線(xiàn)唯笙,一般情況我們繪制文字是不會(huì)超過(guò)這兩條線(xiàn)的螟蒸,但是對(duì)于一些異形字(論壇中經(jīng)常出現(xiàn)的跨樓層的字)是可以超出這兩條線(xiàn)的
- 再則是center線(xiàn),這條線(xiàn)也很好理解崩掘,它就是top和bottom的中心
- 最后就是基線(xiàn)了七嫌,這也是我們
繪制文字時(shí),傳入的y坐標(biāo)
1.1 基線(xiàn)的計(jì)算
解釋了上面六條線(xiàn)的作用苞慢,接下來(lái)再說(shuō)說(shuō)這六條線(xiàn)是怎么計(jì)算的诵原。
首先,我們要清楚挽放,這六條線(xiàn)都是真實(shí)存在的绍赛,它們的值就保存在
Paint.FontMetrics
和Paint.FontMetricsInt
中,這兩個(gè)類(lèi)的值基本相似辑畦,區(qū)別是一個(gè)是float
吗蚌,一個(gè)是int
如圖
-
Paint.FontMetrics
-
Paint.FontMetricsInt
明確了這六條線(xiàn)值的位置,那它們是怎么計(jì)算得來(lái)的呢纯出?
首先說(shuō)明蚯妇,計(jì)算著六條線(xiàn)的時(shí)候,是以基線(xiàn)為參照物的潦刃,計(jì)算方式如下
注:在以下計(jì)算推斷中侮措,ascent,desent之類(lèi)的都表示距離乖杠,ascent.y分扎,desent.y之類(lèi)的表示坐標(biāo)
top.y = top.y - baseline.y
bottom.y = bottom.y - baseline.y
ascent.y = ascent.y - baseline.y
desent.y = desent.y - baseline.y
center.y = (bottom.y - top.y) / 2
因?yàn)槭且詁aseline為參照物,所以所有的距離都是它們的y坐標(biāo)和baseline的y坐標(biāo)相減胧洒,
但是Paint.FontMetrics中并沒(méi)有baseline的值畏吓,那么我們要怎么得到它呢
baseline的計(jì)算如圖所示(網(wǎng)上好多圖都是錯(cuò)的墨状,不得不自己畫(huà)了一張,(╥﹏╥))
首先菲饼,如果我們要繪制文本肾砂,那么我們可以拿到top和bottom的坐標(biāo),并且我們也知道center
- center.y = (bottom.y - top.y) / 2
看圖宏悦,我們知道top.y到center.y的距離和bottom.y到center.y的距離相同镐确,設(shè)定這個(gè)距離為a,那么center.y到baseline.y的距離就是:a - bottom
(沒(méi)有.y時(shí)表示它到baseline的距離)
所以有:
- baseline.y - center.y = (bottom.y - top.y) / 2 - bottom.y
解得:
- baseline.y = center.y + (bottom.y - top.y) / 2 - bottom.y
當(dāng)然饼煞,同樣的推理源葫,還可以得出baseline和ascent,desent之間的關(guān)系砖瞧,這里就不展開(kāi)了息堂,原理都是一樣的
1.2 如何繪制文字到中心
經(jīng)歷了前面的長(zhǎng)篇大論,有的同學(xué)就要問(wèn)了块促,知道baseline的計(jì)算有什么用呢荣堰?
回到最開(kāi)始的api
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
是不是有的同學(xué)在使用這個(gè)api的時(shí)候,經(jīng)常遇到y(tǒng)值怎么設(shè)置都不能讓文字處于控件中間竭翠,不是高一點(diǎn)就是低一點(diǎn)振坚?
如果我們想把文字繪制到我們View的正中心,那么這里的y就需要傳入我們計(jì)算好的baseline逃片,代碼如下
// 首先設(shè)置paint的文字大小
paint.setColor(textColor);
paint.setStrokeWidth(0);
paint.setTextSize(textSize);
paint.setTypeface(Typeface.DEFAULT_BOLD);
//根據(jù)paint的文字大小獲得Paint.FontMetricsInt
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
//根據(jù)Paint.FontMetricsInt計(jì)算baseline
canvas.drawText(string, getWidth() / 2 - paint.measureText(string) / 2 ,
getHeight() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
這樣屡拨,就可以將文字畫(huà)到垂直方向的正中心了,至于水平中心褥实,只需要控件寬度減去文字寬度除以2就可以了
本來(lái)還想寫(xiě)一些文字的特效的,想來(lái)篇幅太長(zhǎng)閱讀起來(lái)體驗(yàn)也不太好裂允,文字的特效就留到以后寫(xiě)吧