使用Paint實現(xiàn)的文字繪制(文字的基線)
請尊重原創(chuàng),轉(zhuǎn)載請注明出處【tianyl】的博客
關(guān)于的Android之玩轉(zhuǎn)View目錄
前言
上篇文章介紹了一些使用Paint和Shader結(jié)合實現(xiàn)的一些特效,不過都是一些圖像繪制方面的,當然,Paint除了能夠進行圖像繪制之外,還有另外一個功能,就是文字的繪制
當然,在學習Paint繪制文字之前,最好能夠熟悉一些Paint繪制文字的api這是Paint繪制文字的常用api說明
1 文字的基線
說到文字繪制,先從一個api說起
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
這是一個常用的繪制文字的辦法,可能有朋友會遇到,在使用這個方法繪制文字的時候,文字的位置經(jīng)常不對,不是高了,就是低了,這就是由于這個api中的x和y造成的
看圖說明

在我們繪制文字的時候,通常有上圖中的六條線,分別是
- top:頂點線
- ascent:建議頂點線
- center:中心線
- baseline:基線
- descent:建議底部線
- bottom:底部線
這六條線分別起什么作用呢?
- 首先是top和bottom,這兩條線很好理解,它分別是頂端和底端,繪制文字時肯定不會超過這兩條線
- 然后是ascent和descent,這兩條線是建議的頂點線和建議底端線,一般情況我們繪制文字是不會超過這兩條線的,但是對于一些異形字(論壇中經(jīng)常出現(xiàn)的跨樓層的字)是可以超出這兩條線的
- 再則是center線,這條線也很好理解,它就是top和bottom的中心
- 最后就是基線了,這也是我們
繪制文字時,傳入的y坐標
1.1 基線的計算
解釋了上面六條線的作用,接下來再說說這六條線是怎么計算的。
首先,我們要清楚,這六條線都是真實存在的,它們的值就保存在
Paint.FontMetrics和Paint.FontMetricsInt中,這兩個類的值基本相似,區(qū)別是一個是float,一個是int
如圖
-
Paint.FontMetrics
-
Paint.FontMetricsInt
明確了這六條線值的位置,那它們是怎么計算得來的呢?
首先說明,計算著六條線的時候,是以基線為參照物的,計算方式如下
注:在以下計算推斷中,ascent,desent之類的都表示距離,ascent.y,desent.y之類的表示坐標
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
因為是以baseline為參照物,所以所有的距離都是它們的y坐標和baseline的y坐標相減,
但是Paint.FontMetrics中并沒有baseline的值,那么我們要怎么得到它呢
baseline的計算如圖所示(網(wǎng)上好多圖都是錯的,不得不自己畫了一張,(╥﹏╥))

首先,如果我們要繪制文本,那么我們可以拿到top和bottom的坐標,并且我們也知道center
- center.y = (bottom.y - top.y) / 2
看圖,我們知道top.y到center.y的距離和bottom.y到center.y的距離相同,設(shè)定這個距離為a,那么center.y到baseline.y的距離就是:a - bottom
(沒有.y時表示它到baseline的距離)
所以有:
- baseline.y - center.y = (bottom.y - top.y) / 2 - bottom.y
解得:
- baseline.y = center.y + (bottom.y - top.y) / 2 - bottom.y
當然,同樣的推理,還可以得出baseline和ascent,desent之間的關(guān)系,這里就不展開了,原理都是一樣的
1.2 如何繪制文字到中心
經(jīng)歷了前面的長篇大論,有的同學就要問了,知道baseline的計算有什么用呢?
回到最開始的api
drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
是不是有的同學在使用這個api的時候,經(jīng)常遇到y(tǒng)值怎么設(shè)置都不能讓文字處于控件中間,不是高一點就是低一點?
如果我們想把文字繪制到我們View的正中心,那么這里的y就需要傳入我們計算好的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計算baseline
canvas.drawText(string, getWidth() / 2 - paint.measureText(string) / 2 ,
getHeight() / 2 +(fm.bottom - fm.top)/2 - fm.bottom, paint);
這樣,就可以將文字畫到垂直方向的正中心了,至于水平中心,只需要控件寬度減去文字寬度除以2就可以了
本來還想寫一些文字的特效的,想來篇幅太長閱讀起來體驗也不太好,文字的特效就留到以后寫吧

