TextPaint是paint的子類,用它能夠很方便的進行文字的繪製,通常狀況下遇到繪製文字的需求時,咱們通常用TextPaint所提供的方法。開始學習如何繪製文字以前,咱們必需要先了解下android中文字是怎麼繪製到屏幕上的,文字的格式又是怎麼樣的。html
1.1 理論知識java
它是一個Paint的內部類,做用是「字體測量」。它裏面呢就定義了top,ascent,descent,bottom,leading五個成員變量其餘什麼也沒有,和rect很類似。若是你不信,咱們能夠去看看源碼:android
/** * Class that describes the various metrics for a font at a given text size. * Remember, Y values increase going down, so those values will be positive, * and values that measure distances going up will be negative. This class * is returned by getFontMetrics(). */ public static class FontMetrics { /** * The maximum distance above the baseline for the tallest glyph in * the font at a given text size. */ public float top; /** * The recommended distance above the baseline for singled spaced text. */ public float ascent; /** * The recommended distance below the baseline for singled spaced text. */ public float descent; /** * The maximum distance below the baseline for the lowest glyph in * the font at a given text size. */ public float bottom; /** * The recommended additional space to add between lines of text. */ public float leading; }
爲了很好的理解這5個變量的意義,咱們用下面的圖示來進行說明。canvas
Baseline是基線,在Android中,文字的繪製都是從Baseline處開始的,Baseline往上至字符「最高處」的距離咱們稱之爲ascent(上坡度),Baseline往下至字符「最低處」的距離咱們稱之爲descent(下坡度);緩存
leading(行間距)則表示上一行字符的descent到該行字符的ascent之間的距離;eclipse
top和bottom文檔描述地很模糊,其實這裏咱們能夠借鑑一下TextView對文本的繪製,TextView在繪製文本的時候總會在文本的最外層留出一些內邊距,爲何要這樣作?由於TextView在繪製文本的時候考慮到了相似讀音符號,下圖中的A上面的符號就是一個拉丁文的相似讀音符號的東西:ide
top的意思其實就是除了Baseline到字符頂端的距離外還應該包含這些符號的高度,bottom的意思也是同樣。通常狀況下咱們極少使用到相似的符號因此每每會忽略掉這些符號的存在,可是Android依然會在繪製文本的時候在文本外層留出必定的邊距,這就是爲何top和bottom總會比ascent和descent大一點的緣由。而在TextView中咱們能夠經過xml設置其屬性android:includeFontPadding="false"去掉必定的邊距值可是不能徹底去掉。學習
1.2 代碼驗證測試
爲了測試一下上述的理論是否正確,咱們寫下了下面的代碼:字體
private static final String TEXT = "ap卡了ξτβбпшㄎㄊěǔぬも┰┠№@↓";
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mTextPaint.setTextSize(50); mTextPaint.setColor(Color.BLACK); FontMetrics fontMetrics = mTextPaint.getFontMetrics(); Log.d("Aige", "ascent:" + fontMetrics.ascent); Log.d("Aige", "top:" + fontMetrics.top); Log.d("Aige", "leading:" + fontMetrics.leading); Log.d("Aige", "descent:" + fontMetrics.descent); Log.d("Aige", "bottom:" + fontMetrics.bottom); mTextPaint.clearShadowLayer(); canvas.drawText(TEXT, 0, Math.abs(fontMetrics.top), mTextPaint); }
結果:
打印的Log:
ascent:-46.38672
top:-52.807617
leading:0.0
descent:12.207031
bottom:13.549805
注:Baseline上方的值爲負,下方的值爲正
咱們來分析一下這個結果:
由於基線上方爲負,因此ascent和top的值都是負數,並且top要大於ascent,緣由是要爲符號留出位置。
由於只有一行文本因此leading恆爲0。
基線下方爲正,因此descent和bottom都是正的,bottom要略大於descent
在獲得的結果中,咱們發現文字是牢牢貼着屏幕頂端的,再看下咱們的程序代碼:
canvas.drawText(TEXT, 0, Math.abs(fontMetrics.top), mTextPaint);
x座標是0,y座標是Math.abs(fontMetrics.top),由於android是從基線開始繪製的,因此咱們爲了讓字體頂端緊貼屏幕就必須讓它移下來一點,移動的距離是top的距離,也就是基線到文字對頂部的距離。有人可能會問,若是不設置呢?x,y座標都是0,是什麼效果呢?由於android會從基線開始繪製,因此若是不作處理,基線就是屏幕的頂部,所以會出現以下的效果:
最終,咱們驗證了上面的理論是徹底正確的。
1.3 fontMetrics中的變量和文字的size、typeface有關
從代碼中咱們能夠看到一個很特別的現象,在咱們繪製文本以前咱們即可以獲取文本的FontMetrics屬性值,也就是說咱們FontMetrics的這些值跟咱們要繪製什麼文本是無關的,而僅與繪製文本Paint的size和typeface有關。當你改變了paint繪製文字的size或typeface時,FontMetrics中的top、bottom等值就會發生改變。若是咱們僅僅更改了文字,這些值是不會發生任何改變的。
1.4 繪製居中屏幕的文字
咱們知道了這些理論知識,也知道android是怎麼繪製文字的,一會咱們要作一個實際的例子來鞏固鞏固。首先,咱們要先來擴展認識兩個方法:
解釋:the distance below (positive) the baseline (descent) based on the current typeface and text size.一句話解釋:獲得下坡度的值解釋:the distance above (negative) the baseline (ascent) based on the current typeface and text size.
一句話解釋:就是獲得上坡度的值
實際代碼:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mTextPaint.setTextSize(50); mTextPaint.setColor(Color.BLACK); // 計算Baseline繪製的起點X軸座標 ,計算方式:畫布寬度的一半 - 文字寬度的一半 int baseX = (int) (canvas.getWidth() / 2 - mTextPaint.measureText(TEXT) / 2); // 計算Baseline繪製的Y座標 ,計算方式:畫布高度的一半 - 文字總高度的一半 int baseY = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)); // 居中畫一個文字 canvas.drawText(TEXT, baseX, baseY, mTextPaint); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(2); // 爲了便於理解咱們在畫布中心處繪製一條中線 canvas.drawLine(0, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight() / 2, mPaint); }
咱們計算了x座標和y座標。
x座標的計算方法是(屏幕寬度-文字寬度)/2,若是文字寬度比屏幕寬度長獲得的就是負數,若是文字寬度比屏幕寬度短,獲得的就是正數,這個很容易理解;
y座標的的計算方式是(屏幕高度-文字高度)/2,這裏的文字高度用的是:descent+ascent(忽略了音標)。
結果:
2、TextPaint中的各類方法
顧名思義就是返回上坡度的值
float descent()
獲得下坡度的值
這個方法讓咱們設置一個最大寬度,在不超過這個寬度的範圍內返回實際測量值不然中止測量。
text表示咱們的字符串;
start表示從第幾個字符串開始測量;
end表示從測量到第幾個字符串爲止;
measureForwards表示向前仍是向後測量;
maxWidth表示一個給定的最大寬度在這個寬度內能測量出幾個字符;
measuredWidth爲一個可選項,能夠爲空,不爲空時返回真實的測量值
這些方法在一些結合文本處理的應用裏比較經常使用,好比文本閱讀器的翻頁效果,咱們須要在翻頁的時候動態折斷或生成一行字符串,這就派上用場了~
獲得一個FontMetrics對象。
這個和咱們以前用到的getFontMetrics()相比多了個參數,getFontMetrics()返回的是FontMetrics對象,而getFontMetrics(Paint.FontMetrics metrics)返回的是文本的行間距,若是metrics的值不爲空則返回FontMetrics對象的值。
該方法返回了一個FontMetricsInt對象,FontMetricsInt和FontMetrics是同樣的,只不過getFontMetricsInt()獲得的對象中的參數都是int類型,而getFontMetrics()返回對象中的參數都是float。
獲得文字的間距,距離是int類型
返回字符行間距
設置文字的下劃線
設置字體類型,上面咱們也使用過。
Android中字體有四種樣式:BOLD(加粗),BOLD_ITALIC(加粗並傾斜),ITALIC(傾斜),NORMAL(正常);
android爲咱們提供的字體有五種:DEFAULT,DEFAULT_BOLD,MONOSPACE,SANS_SERIF和SERIF,咱們也能夠用本身定義的字體:
Paint p = new Paint(); String familyName = "宋體"; Typeface font = Typeface.create(familyName, Typeface.BOLD); p.setColor(Color.RED); p.setTypeface(font);
設置文本在水平方向上的傾斜。這個傾斜值沒有具體的範圍,可是官方推崇的值爲-0.25能夠獲得比較好的傾斜文本效果,值爲負右傾值爲正左傾,默認值爲0。
設置文字的大小,可是要注意該值必需大於零。
將文本沿X軸水平縮放,默認值爲1,當值大於1會沿X軸水平放大文本,當值小於1會沿X軸水平縮放文本
// 設置畫筆文本傾斜 textPaint.setTextScaleX(0.5F);
// 設置畫筆文本傾斜 textPaint.setTextScaleX(1.5F);
注意:setTextScaleX不只放大了文本寬度同時還拉伸了字符!這是亮點~
設置地理位置,這裏若是你要使用,直接傳入Locale.getDefault()便可。
設置文本的對齊方式,可供選的方式有三種:CENTER,LEFT和RIGHT。
咱們的文本大小是經過size和typeface肯定的(其實還有其餘的因素但這裏影響不大忽略),一旦baseline肯定,對不對齊好像不相干吧。可是,你要知道一點,文本的繪製是從baseline開始沒錯,可是是從哪邊開始繪製的呢?左端仍是右端呢?而這個Align就是爲咱們定義在baseline繪製文本究竟該從何處開始,上面咱們在進行對文本的水平居中時是用Canvas寬度的一半減去文本寬度的一半:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mTextPaint.setTextSize(50); mTextPaint.setColor(Color.BLACK); // 計算Baseline繪製的起點X軸座標 ,計算方式:畫布寬度的一半 - 文字寬度的一半 int baseX = (int) (canvas.getWidth() / 2 - mTextPaint.measureText(TEXT) / 2); // 計算Baseline繪製的Y座標 ,計算方式:畫布高度的一半 - 文字總高度的一半 int baseY = (int) ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)); // 居中畫一個文字 canvas.drawText(TEXT, baseX, baseY, mTextPaint); mPaint.setColor(Color.RED); mPaint.setStrokeWidth(2); // 爲了便於理解咱們在畫布中心處繪製一條中線 canvas.drawLine(0, canvas.getHeight() / 2, canvas.getWidth(), canvas.getHeight() / 2, mPaint); }
實際上咱們大可沒必要這樣計算,咱們只需設置Paint的文本對齊方式爲CENTER,drawText的時候起點x = canvas.getWidth() / 2便可。產生的效果是,文字先算好一個基準線,從這個基準線的中點開始向左右開始繪製文字,最終天然就變成了居中顯示了。若是你設定了RIGHT,那麼從baseline的右邊的頂點開始,文字開始慢慢繪製。
textPaint.setTextAlign(Align.CENTER);
canvas.drawText(TEXT, canvas.getWidth() / 2, baseY, textPaint);
當咱們將文本對齊方式設置爲CENTER後就至關於告訴Android咱們這個文本繪製的時候從文本的中點開始向兩端繪製;若是設置爲LEFT則從文本的左端開始往右繪製;若是爲RIGHT則從文本的右端開始往左繪製:
設置是否打開文本的亞像素顯示,什麼叫亞像素顯示呢?你能夠理解爲對文本顯示的一種優化技術,若是你們用的是Win7+系統能夠在控制面板中找到一個叫ClearType的設置,該設置可讓你的文本更好地顯示在屏幕上就是基於亞像素顯示技術。
文本刪除線
設置是否打開線性文本標識,這玩意對大多數人來講都很奇怪不知道這玩意什麼意思。想要明白這東西你要先知道文本在Android中是如何進行存儲和計算的。在Android中文本的繪製須要使用一個bitmap做爲單個字符的緩存,既然是緩存一定要使用必定的空間,咱們能夠經過setLinearText (true)告訴Android咱們不須要這樣的文本緩存。
設置文本仿粗體
測量文本寬度,上面咱們已經使用過了,這四個方法都是同樣的只是參數稍有不一樣罷了。
3、Typeface中的方法
最簡單的,簡而言之就是把上面所說的四種Style封裝成Typeface。傳入的參數是:BOLD(加粗),BOLD_ITALIC(加粗並傾斜),ITALIC(傾斜),NORMAL(正常)
mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
textPaint.setTypeface(Typeface.create("SERIF", Typeface.NORMAL));
textPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.NORMAL));
這兩個方法執行的效果徹底同樣。
這三者也是同樣的,它們都容許咱們使用本身的字體好比咱們從asset目錄讀取一個字體文件。下面是一個簡單的例子:
// 獲取字體並設置畫筆字體 Typeface typeface = Typeface.createFromAsset(context.getAssets(), "kt.ttf"); textPaint.setTypeface(typeface);
3.2 擴展到TextView
說到文本你們第一時間想到的應該是TextView,其實在TextView裏咱們依然能夠找到上面不少方法的影子,好比咱們能夠從TextView中獲取到TextPaint:
TextPaint paint = mTextView.getPaint();
固然也能夠設置TextView的字體等等:
Typeface typeface = Typeface.createFromAsset(getAssets(), "kt.ttf");
mTextView.setTypeface(typeface);
說明:本文大部份內容來自:http://blog.csdn.net/aigestudio/article/details/41447349,我對原文進行了少許修改,記錄在此。
From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 尊重原做者,感謝做者的分享!