Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 使用TextPaint來繪制文字

使用TextPaint來繪制文字

編輯:關於Android編程

TextPaint是paint的子類,用它可以很方便的進行文字的繪制,一般情況下遇到繪制文字的需求時,我們一般用TextPaint所提供的方法。開始學習如何繪制文字之前,我們必須要先了解下android中文字是怎麼繪制到屏幕上的,文字的格式又是怎麼樣的。

一、FontMetrics(字體度量)
1.1理論知識
它是一個Paint的內部類,作用是“字體測量”。它裡面呢就定義了top,ascent,descent,bottom,leading五個成員變量其他什麼也沒有,和rect很相似。如果你不信,我們可以去看看源碼:

 /**
     * 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個變量的意義,我們用下面的圖示來進行說明。
這裡寫圖片描述

Baseline是基線
在Android中,文字的繪制都是從Baseline處開始的<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPqOsPHN0cm9uZz5CYXNlbGluZc35yc/WwdfWt/smbGRxdW871+6437SmJnJkcXVvO7XEvuDA687Sw8ezxtauzqphc2NlbnSjqMnPxsK2yKOpo6xCYXNlbGluZc35z8LWwdfWt/smbGRxdW871+61zbSmJnJkcXVvO7XEvuDA687Sw8ezxtauzqpkZXNjZW50o6jPwsbCtsijqTwvc3Ryb25nPqO7PC9wPg0KPHA+PHN0cm9uZz5sZWFkaW5no6jQ0LzkvuCjqdTyse3KvsnP0rvQ0NfWt/u1xGRlc2NlbnS1vbjD0NDX1rf7tcRhc2NlbnTWrrzktcS+4MDrPC9zdHJvbmc+o7s8L3A+DQo8cD6hoaGhPHN0cm9uZz50b3C6zWJvdHRvbc7EtbXD6Mr2tdi63MSjuv2jrMbkyrXV4sDvztLDx7/J0tS96Lz40rvPwlRleHRWaWV3ttTOxLG+tcS75tbGo6xUZXh0Vmlld9Tau+bWxs7Esb61xMqxuvLX3Lvh1NrOxLG+tcTX7s3isuPB9LP20rvQqcTasd++4KOszqrKssO00qrV4tH51/ajv9LyzqpUZXh0Vmlld9Tau+bWxs7Esb61xMqxuvK/vMLHtb3By8Dgy8a2wdL0t/u6xaOsz8LNvNbQtcRByc/D5rXEt/u6xb7NysfSu7j2wK22oc7EtcTA4MvGtsHS9Lf7usW1xLarzvc8L3N0cm9uZz6jujxiciAvPg0KoaGhoTxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20161021/201610211009491477.png" title="\" />
  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 繪制居中屏幕的文宗喎?/kf/yidong/wp/" target="_blank" class="keylink">WPGJyIC8+DQrO0sPH1qq1wMHL1eLQqcDtwtvWqsq2o6zSstaqtcBhbmRyb2lkysfU9cO0u+bWxs7E19a1xKOs0ru74c7Sw8fSqtf20ru49sq1vMq1xMD919PAtLmuucy5rrnMoaPK18/Io6zO0sPH0qrPyMC0wKnVucjPyrbBvbj2t723qKO6PC9wPg0KPHByZSBjbGFzcz0="brush:java;"> float android.graphics.Paint.descent() 解釋:the distance below (positive) the baseline (descent) based on the current typeface and text size. 一句話解釋:得到下坡度的值 float android.graphics.Paint.ascent() 解釋: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坐標的計算方法是(屏幕寬度-文字寬度)/2,如果文字寬度比屏幕寬度長得到的就是負數,如果文字寬度比屏幕寬度短,得到的就是正數,這個很容易理解;

y坐標的的計算方式是(屏幕高度-文字高度)/2,這裡的文字高度用的是:descent+ascent(忽略了音標)。

結果:
這裡寫圖片描述

這裡的TextPaint.FontMetrics(); 就是幫助我們得到我們字體的各種距離屬性的,然後方便我們對文字進行繪制。
這裡我們需要牢記的就是TOP ASCENT DESCENT BOTTOM LEADING等等屬性值。這些都可以讓我們在自定義View的時候畫Text更得心應手,更精確。

二、TextPaint中的各種方法

float ascent():顧名思義就是返回上坡度的值
float descent():得到下坡度的值

public int breakText (String text, boolean measureForwards, float maxWidth, float[] measuredWidth)
public int breakText (char[] text, int index, int count, float maxWidth, float[] measuredWidth)
public int breakText (CharSequence text, int start, int end, boolean measureForwards, float maxWidth, float[] measuredWidth)

這個方法讓我們設置一個最大寬度,在不超過這個寬度的范圍內返回實際測量值否則停止測量。
**text表示我們的字符串;
start表示從第幾個字符串開始測量;
end表示從測量到第幾個字符串為止;
measureForwards表示向前還是向後測量;
maxWidth表示一個給定的最大寬度在這個寬度內能測量出幾個字符;
measuredWidth為一個可選項,可以為空,不為空時返回真實的測量值**

這些方法在一些結合文本處理的應用裡比較常用,比如文本閱讀器的翻頁效果,我們需要在翻頁的時候動態折斷或生成一行字符串,這就派上用場了~

getFontMetrics();//得到一個FontMetrics對象。 然後可以得到這個對象下面對於文字測量所需要的一些數值。

**getFontMetrics (Paint.FontMetrics metrics)
這個和我們之前用到的getFontMetrics()相比多了個參數,getFontMetrics()返回的是FontMetrics對象,而getFontMetrics(Paint.FontMetrics metrics)返回的是文本的行間距,如果metrics的值不為空則返回FontMetrics對象的值。**

**getFontMetricsInt()
該方法返回了一個FontMetricsInt對象,FontMetricsInt和FontMetrics是一樣的,只不過getFontMetricsInt()得到的對象中的參數都是int類型,而getFontMetrics()返回對象中的參數都是float。**

**getFontMetricsInt(Paint.FontMetricsInt fmi)
得到文字的間距,距離是int類型**

getFontSpacing();//返回字符行間距

setUnderlineText(boolean underlineText);//設置文字的下劃線

setTypeface(Typeface typeface);//設置字體類型,上面我們也使用過。
Android中字體有四種樣式:BOLD(加粗),BOLD_ITALIC(加粗並傾斜),ITALIC(傾斜),NORMAL(正常); 這四個是靜態常量,直接傳入即可 和WORD是很像的。

  **Paint p = new Paint();  
     String familyName = "宋體";  
     **Typeface** font = Typeface.create(familyName, Typeface.BOLD);  
     p.setColor(Color.RED);  
     p.setTypeface(font);** 

setTextSkewX(float skewX)

設置文本在水平方向上的傾斜。這個傾斜值沒有具體的范圍,但是官方推崇的值為-0.25可以得到比較好的傾斜文本效果,值為負右傾值為正左傾,默認值為0。

setTextSize (float textSize)
設置文字的大小,但是要注意該值必需大於零。

setTextScaleX (float scaleX)
將文本沿X軸水平縮放,默認值為1,當值大於1會沿X軸水平放大文本,當值小於1會沿X軸水平縮放文本

setTextLocale (Locale locale)
設置地理位置,這裡如果你要使用,直接傳入Locale.getDefault()即可。

setTextAlign (Paint.Align align)
設置文本的對齊方式,可供選的方式有三種: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則從文本的右端開始往左繪制:
這裡寫圖片描述系統可以在控制面板中找到一個叫ClearType的設置,該設置可以讓你的文本更好地顯示在屏幕上就是基於亞像素顯示技術。

setStrikeThruText (boolean strikeThruText);//文本刪除線

**setLinearText (boolean linearText)
設置是否打開線性文本標識,這玩意對大多數人來說都很奇怪不知道這玩意什麼意思。想要明白這東西你要先知道文本在Android中是如何進行存儲和計算的。在Android中文本的繪制需要使用一個bitmap作為單個字符的緩存,既然是緩存必定要使用一定的空間,我們可以通過setLinearText (true)告訴Android我們不需要這樣的文本緩存。**

setFakeBoldText (boolean fakeBoldText);//設置文本仿粗體

measureText (String text)
measureText (CharSequence text, int start, int end)
measureText (String text, int start, int end)
measureText (char[] text, int index, int count)
測量文本寬度,上面我們已經使用過了,這四個方法都是一樣的只是參數稍有不同罷了。

三、Typeface中的方法

defaultFromStyle(int style)
最簡單的,簡而言之就是把上面所說的四種Style封裝成Typeface。傳入的參數是:BOLD(加粗),BOLD_ITALIC(加粗並傾斜),ITALIC(傾斜),NORMAL(正常)

mTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));

create(String familyName, int style)
create(Typeface family, int style)
**textPaint.setTypeface(Typeface.create(“SERIF”, Typeface.NORMAL));
textPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.NORMAL));**
這兩個方法執行的效果完全一樣。

**createFromAsset(AssetManager mgr, String path)
createFromFile(String path)
createFromFile(File path)
這三者也是一樣的,它們都允許我們使用自己的字體比如我們從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);

其實寫到這裡,我希望大家能清楚這樣一個概念,在Android的View上進行繪制文字,和我們在Word上繪制是一樣的,我們有的時候需要對文字的各種屬性進行設置,那麼我們的TextPaint同樣提供這些方法, 這要和WORD相對應就可以了,不要把這個類想的很復雜,他就是一個代碼化的WORD他甚至比WORD更精確靈活,讓你隨心所欲的對文字進行處理。

那麼常用的就是:我們選擇我們喜歡的字體 這裡的格式是 ttf把文字放到asset當中就可以了
我們設置文字的位置,那麼這個屬性就是Align
我們設置文字的大小,TextSize
我們設置文字的顏色,TextColor
等等只要你需要的這個類都會提供相應的方法給你!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved