一、概述
1. 四線格與基線
小時候,我們在剛開始學習寫字母時,用的本子是四線格的,我們必須把字母按照規則寫在四線格內。
比如:
那么問題來了,在canvas在利用drawText繪制文字時,也是有規則的,這個規則就是baseline(基線)!
我們先來看一下什么是基線:
對比以上兩圖,可見基線就是四線格中的第三條線!也就是說,只要基線的位置定了,那文字的位置必然是定了的!
2. canvas.drawText()
(1)canvas.drawText()與基線
下面我們來看看canvas.drawText()這個函數
/**
* text:要繪制的文字
* x:繪制原點x坐標
* y:繪制原點y坐標
* paint:用來做畫的畫筆
*/
public void drawText(String text, float x, float y, Paint paint)
上面這個構造函數是最常用的drawText方法,傳進去一個String對象就能畫出對應的文字。
但這里有兩個參數需要非常注意,表示原點坐標的x和y.很多同學可能會認為,這里傳進去的原點參數(x,y)是所在繪制文字所在矩形的左上角的點。但實際上并不是!比如,我們上面如果要畫“matt’s blog”這幾個字,這個原點坐標應當是下圖中綠色小點的位置
(2)實例
下面我們就舉個例子來看一下drawText中,原點坐標(x,y)的位置。
新建一個工程,創建一個MainActivity,然后創建一個CustomTextView繼承View
重寫onDraw函數
//重寫onDraw函數,自定義一個基線,然后利用drawText畫出來
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineX = 0 ;
int baseLineY = 200;
//畫基線
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
}
在這里,先定義drawText原點的位置:(0,200)
首先,我們把(0,200)所在的這條橫線畫出來,所以我先畫了一條線從點坐標為(0,200)到點坐標為(2500,200)的一條直線
然后利用canvas.drawText以(0,200)為原點畫出文字
在main.xml添加自定義view的引用
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_main"
tools:context="cn.addapp.customviews.MainActivity">
android:layout_width="match_parent"
android:layout_height="match_parent"/>
效果圖如下:
結論:
1. drawText是中的參數y是基線的位置。
2. 一定要清楚的是,只要x坐標、基線位置、文字大小確定以后,文字的位置就是確定的了。
3. paint.setTextAlign(Paint.Align.XXX)
在上面我們講了,drawText()函數中的Y坐標表示所要繪制文字的基線所在位置。從上面的例子,我們可以看到,我們繪圖結果是在X坐標的右邊開始繪制的,但這并不是必然的結果。
我們來看一張圖:
我們知道,我們在drawText(text, x, y, paint)中傳進去的源點坐標(x,y);其中,y表示的基線的位置。那x代表什么呢?從上面的例子運行結果來看,應當是文字開始繪制的地方。
并不是所要繪制文字所在矩形的相對位置。相對位置就是指定點(x,y)在在所要繪制矩形的位置。我們知道所繪制矩形的縱坐標是由Y值來確定的,而相對x坐標的位置,只有左、中、右三個位置了。也就是所繪制矩形可能是在x坐標的左側繪制,也有可能在x坐標的中間,也有可能在x坐標的右側。而定義在x坐標在所繪制矩形相對位置的函數是:
/**
* 其中Align的取值為:Panit.Align.LEFT,Paint.Align.CENTER,Paint.Align.RIGHT
*/
paint.setTextAlign(Align align);
我們再來重新看一下上面的例子,當我們設置為不同的值時,繪制結果是怎樣的。
同樣的代碼,我們加上paint.setTextAlign()來設置相對位置來看看結果。
(1)setTextAlign(Paint.Align.LEFT)
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineY = 200;
int baseLineX = 0 ;
//畫基線
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
}
運行結果如下:
可見,原點(x,y)在矩形的左側,即矩形從(x,y)的點開始繪制
(2)setTextAlign(Paint.Align.CENTER)
同樣的代碼,把相對位置設置為:setTextAlign(Paint.Align.CENTER)
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineY = 200;
int baseLineX = 0 ;
//畫基線
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
}
運行結果如下:
所以原點(x,y)就在所要繪制文字所在矩形區域的正中間,換句話說,系統會根據(x,y)的位置和文字所在矩形大小,會計算出當前開始繪制的點。以使原點(x,y)正好在所要繪制的矩形的正中間。
(3)setTextAlign(Paint.Align.RIGHT)
同樣的代碼,把相對位置設置為:setTextAlign(Paint.Align.RIGHT)
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineY = 200;
int baseLineX = 0 ;
//畫基線
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.RIGHT);
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
}
運行結果如下:
所以原點(x,y)應當在所要繪制矩形的右側,在上面的代碼中,也就是說整個矩形都在(0,200)的左側,所以我們看到的是什么都沒有。
(4)注意
下面,我們再看一個例子:
我們只寫一個大寫字母 M,然后將其相對位置設置為paint.setTextAlign(Paint.Align.CENTER)
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineY = 200;
int baseLineX = 0 ;
//畫基線
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("M", baseLineX, baseLineY, paint);
}
運行結果如下:
我們可以看到字母M在原點(0,200)的正中間。
這也就是我們要強調的:相對位置是根據所要繪制文字所在矩形來計算的。
二、drawText的四線格與FontMetrics
1、Text的繪圖四線格
前面我們講了基線,其實除了基線,系統在繪制Text時,還是有其它線的,我們來看個圖:
除了基線以外,如上圖所示,另外還有四條線,分別是ascent,descent,top,bottom,他們的意義分別是:
ascent: 系統建議的,繪制單個字符時,字符應當的最高高度所在線
descent:系統建議的,繪制單個字符時,字符應當的最低高度所在線
top: 可繪制的最高高度所在線
bottom: 可繪制的最低高度所在線
單從這幾個定義,大家可能還是搞不清這幾值到底是什么意義。我們來看一下電視的顯示。用過視頻處理工具的同學(比如premiere,AE,繪聲繪影等),應該都會知道,在制作視頻時,視頻顯示位置都會有一個安全區域框,如下圖所示:
如上圖所示,黑色部分表示電視屏幕,紅色框就表示安全區域框。
這個安全框是用來干嘛的?這個安全框就是系統推薦給我們的顯示區域,雖然說我們可以講電視屏幕是每個區域都是可以顯示圖像的,但由于制式的不同,每個國家的屏幕大小并不一定我們這里的屏幕大小一致,當遇到不一致時,就會裁剪。但系統給我們推薦的顯示區域是無論哪種制式都是可以完整顯示出來的,所以我們在制作視頻時,盡量要把要顯示的圖像放在所推薦的顯示區域內。
同樣,在這里,我們在繪制文字時,ascent是推薦的繪制文字的最高高度,就表示在繪制文字時,盡力要在這個最高高度以下繪制文字。descent是推薦的繪制文字的最底高度線,同樣表示是在繪制文字時盡量在這個descent線以上來繪制文字。而top線則指該文字可以繪制的最高高度線,bottom則是表示該文字可以繪制的最低高度線。ascent,descent是系統建議上的繪制高度,而top,bottom則是物理上屏幕最高,最低可以畫的高度值。他們的差別與我們上面說的視頻處理的安全框和屏幕的道理是一樣的。
2、FontMetrics
(1)、fontMetrics概述
上面我們講了,系統在畫文字時的五條線,baseline、ascent、descent、top、bottom我們知道baseline的位置是我們在構造drawText()時的參數y來決定的,那ascent,descent,top,bottom這些線的位置要怎么計算出來呢?
Android給我們提供了一個類:FontMetrics,它里面有四個成員變量:
FontMetrics::ascent;
FontMetrics::descent;
FontMetrics::top;
FontMetrics::bottom;
他們的意義與值的計算方法分別如下:
ascent = ascent線的y坐標 - baseline線的y坐標;
descent = descent線的y坐標 - baseline線的y坐標;
top = top線的y坐標 - baseline線的y坐標;
bottom = bottom線的y坐標 - baseline線的y坐標;
我們再來看這個圖:
從這個圖中,我們先說明兩點,然后再回過頭來看上面的公式:
1、X軸,Y軸的正方向走向是X軸向右是正方向,Y軸向下是正方向,所以越往右X坐標越大,越往下Y坐標越大!
2、大家千萬不要將FontMetrics中的ascent,descent,top,bottom與現實中的ascent,descent,top,bottom所在線混淆!
這幾條線是真實存在的,而FontMetrics中的ascent,descent,top,bottom這個變量的值就是用來計算這幾條線的位置的。下面我們將看到如何利用這幾個變量來計算這幾條線的位置。
看完這個圖,我們再重新說說這幾個公式,我們拿一個來說吧,其它都是相同的道理。
ascent = ascent線的y坐標 - baseline線的y坐標;
FontMetrics的這幾個變量的值都是以baseline為基準的,對于ascent來說,baseline線在ascent線之下,所以必然baseline的y值要大于ascent線的y值,所以ascent變量的值是負的。
同理,對于descent而言:
descent = descent線的y坐標 - baseline線的y坐標;
descent線在baseline線之下,所以必然descent線的y坐標要大于baseline線的y坐標,所以descent變量的值必然是正數。
(2)、得到Text四線格的各線位置
下面,我們就來看看如何通過這些變量來得到對應線所在位置吧。
我們先列出來一個公式:
ascent線Y坐標 = baseline線Y坐標 + fontMetric.ascent;
推算過程如下:
因為ascent線的Y坐標等于baseline線的Y坐標減去從baseline線到ascent線的這段距離。
也就是:(|fontMetric.ascent|表示取絕對值)
ascent線Y坐標 = baseline線Y坐標 - |fontMetric.ascent|;
又因為fontMetric.ascent是負值,所以:
ascent線Y坐標 = baseline線Y坐標 - |fontMetric.ascent|;
ascent線Y坐標 = baseline線Y坐標 - ( -fontMetric.ascent);
ascent線Y坐標 = baseline線Y坐標 + fontMetric.ascent;
這就是整個推算過程,沒什么難度,同理可以得到:
ascent線Y坐標 = baseline線的y坐標 + fontMetric.ascent;
descent線Y坐標 = baseline線的y坐標 + fontMetric.descent;
top線Y坐標 = baseline線的y坐標 + fontMetric.top;
bottom線Y坐標 = baseline線的y坐標 + fontMetric.bottom;
(3)、獲取FontMetrics對象
獲取FontMetrics對象是根據paint對象來獲取的:
Paint paint = new Paint();
Paint.FontMetrics fm = paint.getFontMetrics();
Paint.FontMetricsInt fmInt = paint.getFontMetricsInt();
從這里可以看到,通過paint.getFontMetrics()得到對應的FontMetrics對象。這里還有另外一個FontMetrics同樣的類叫做FontMetricsInt,它的意義與FontMetrics完全相同,只是得到的值的類型不一樣而已,FontMetricsInt中的四個成員變量的值都是Int類型,而FontMetrics得到的四個成員變量的值則都是float類型的。
(4)、實例:計算Text四線格位置
在這個例子中,我們先寫一行字,然后畫出這行字中的top線,ascent線,baseline線,descent線和bottom線。
我們直接上完整代碼:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int baseLineY = 200;
int baseLineX = 0 ;
Paint paint = new Paint();
//寫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
//計算各線在位置
Paint.FontMetrics fm = paint.getFontMetrics();
float ascent = baseLineY + fm.ascent;
float descent = baseLineY + fm.descent;
float top = baseLineY + fm.top;
float bottom = baseLineY + fm.bottom;
//畫基線
paint.setColor(Color.parseColor("#FF0000"));
paint.setFakeBoldText(true);
paint.setStrokeWidth(3);
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫top
paint.setColor(Color.parseColor("#196F3D"));
canvas.drawLine(baseLineX, top, 2500, top, paint);
//畫ascent
paint.setColor(Color.parseColor("#1A5276"));
canvas.drawLine(baseLineX, ascent, 2500, ascent, paint);
//畫descent
paint.setColor(Color.parseColor("#F1C40F"));
canvas.drawLine(baseLineX, descent, 2500, descent, paint);
//畫bottom
paint.setColor(Color.parseColor("#33FF00"));
canvas.drawLine(baseLineX, bottom, 2500, bottom, paint);
}
這段代碼中,總共分為三部分,寫文字、計算各線所在位置、畫出各條線;我們逐段來講
先看寫文字:
int baseLineY = 200;
int baseLineX = 0 ;
Paint paint = new Paint();
//寫文字
paint.setColor(Color.BLUE);
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
canvas.drawText("matt's blog", baseLineX, baseLineY, paint);
有關drawText的問題我們已經講過,在這段代碼中,我們需要注意的是兩點:
1、drawText中的參數y是基線的位置
2、paint.setTextAlign(Paint.Align.LEFT);設置的相對位置為,指定的原點(0,200)在繪制矩形的左側。換句話說,所繪制的文字所在矩形在(0,200)點的右側
然后是計算各各線的y坐標位置:
//計算各線在位置
Paint.FontMetrics fm = paint.getFontMetrics();
float ascent = baseLineY + fm.ascent;
float descent = baseLineY + fm.descent;
float top = baseLineY + fm.top;
float bottom = baseLineY + fm.bottom;
首先,利用 paint.getFontMetrics()得到FontMetrics的實例,然后利用我們上面的公式即可得到各條線的y坐標。
最后就是利用這些y坐標畫出這些線了,很簡單,就是drawLine的使用,難度不大,就不再細講。
三、所繪文字寬度、高度和最小矩形獲取
這部分,我們將講解如何獲取所繪制字符串所占區域的高度、寬度和僅包裹字符串的最小矩形。我們來看張圖來講述下他們的意義:
在這張圖中,文字底部的綠色框就是所繪制字符串所占據的大小。我們要求的寬度和高度也就是這個綠色框的寬度和高度。
從圖中也可以看到,紅色框部分,它的寬和高緊緊包圍著字符串,所以紅色框就是我們要求的最小矩形。即能包裹字符串的最小矩形。
1、字符串所占高度和寬度
(1)、高度
字符串所占高度很容易得到,直接用bottom線所在位置的Y坐標減去top線所在位置的Y坐標就是字符串所占的高度:
代碼如下:
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int top = baseLineY + fm.top;
int bottom = baseLineY + fm.bottom;
//所占高度
int height = bottom - top;
(2)、寬度
寬度是非常容易得到的,直接利用下面的函數就可以得到
int width = paint.measureText(String text);
使用示例如下:
String text = "matt's blog";
Paint paint = new Paint();
//設置paint
paint.setTextSize(120); //以px為單位
//獲取寬度
int width = (int)paint.measureText(text);
(3)、最小矩形
1、概述
要獲取最小矩形,也是通過系統函數來獲取的,函數及意義如下:
/**
* 獲取指定字符串所對應的最小矩形,以(0,0)點所在位置為基線
* @param text 要測量最小矩形的字符串
* @param start 要測量起始字符在字符串中的索引
* @param end 所要測量的字符的長度
* @param bounds 接收測量結果
*/
public void getTextBounds(String text, int start, int end, Rect bounds);
我們簡單展示下使用代碼及結果:
String text = "matt's blog";
Paint paint = new Paint();
//設置paint
paint.setTextSize(120); //以px為單位
Rect rect = new Rect();
paint.getTextBounds(text,0,text.length(),rect);
Log.e("matt",rect.toShortString());
在這段代碼中,首先設置字體大小,然后利用paint.getTextBounds()得到最小矩形,最后,我將其打印出來
結果如下:
可以看到這個矩形的左上角位置為(8,-90),右下角的位置為(580,25);
大家可能會有疑問,為什么左上角的Y坐標是個負數?從代碼中,我們也可以看到,我們并沒有給getTextBounds()傳遞基線位置。那它就是以(0,0)為基線來得到這個最小矩形的!所以這個最小矩形的位置就是以(0,0)為基線的結果!
2、得到最小矩形的實際位置
我們先來看一個原理:
在上面這個圖中,我們將黑色矩形平行下移距離Y(黃色線依照的是基線的位置),那么平移后的左上角點的y坐標就是 y2 = y1 + Y;
同樣的道理,由于paint.getTextBounds()得到最小矩形的基線是y = 0;那我們直接將這個矩形移動baseline的距離就可以得到這個矩形實際應當在的位置了。
所以矩形應當所在實際位置的坐標是:
Rect minRect = new Rect();
paint.getTextBounds(text,0,text.length(),minRect);
//最小矩形,實際top位置
int minTop = minRect.top + baselineY;
//最小矩形,實際bottom位置
int minBottom = minRect.bottom + baselineY;
3、實例
下面我們就舉個例子來看一下我們列舉的這幾個函數的使用方法
效果圖與這一節開篇時的效果圖是一樣的,如下:
我們先看一下完整的代碼,然后再細講
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String text = "matt's blog";
int baseLineY = 200;
int baseLineX = 0 ;
//設置paint
Paint paint = new Paint();
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
//畫text所占的區域
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int top = baseLineY + fm.top;
int bottom = baseLineY + fm.bottom;
int width = (int)paint.measureText(text);
Rect rect = new Rect(baseLineX,top,baseLineX+width,bottom);
paint.setColor(Color.GREEN);
canvas.drawRect(rect,paint);
//畫最小矩形
Rect minRect = new Rect();
paint.getTextBounds(text,0,text.length(),minRect);
minRect.top = baseLineY + minRect.top;
minRect.bottom = baseLineY + minRect.bottom;
paint.setColor(Color.RED);
canvas.drawRect(minRect,paint);
//寫文字
paint.setColor(Color.WHITE);
canvas.drawText(text, baseLineX, baseLineY, paint);
}
這段代碼總共分為四部分:設置paint,畫字符串所占據矩形,畫最小矩形,畫文字
第一部分:設置paint
String text = "matt's blog";
int baseLineY = 200;
int baseLineX = 0 ;
//設置paint
Paint paint = new Paint();
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
設置paint這部分,主要是設置字體的大小,因為我們在字體所占的區域大小跟字體的大小是有直接關系的,如果不設置,那么在獲取所占區域大小時,將利用系統默認的大小來測量了,當然是不行的。
第二部分:畫text所占的區域
//畫text所占的區域
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int top = baseLineY + fm.top;
int bottom = baseLineY + fm.bottom;
int width = (int)paint.measureText(text);
Rect rect = new Rect(baseLineX,top,baseLineX+width,bottom);
paint.setColor(Color.GREEN);
canvas.drawRect(rect,paint);
這里就是利用我們前面我們講過的獲取top線和bottom線的方法,獲取寬度時就是利用paint.measureText(text);
然后利用求得到top,bottom,width來得到對應的矩形:Rect(baseLineX,top,baseLineX+width,bottom),這里要注意的是我們利用paint.measureText(text)得到的只是寬度,矩形右下角的x坐標值為baselinex+width;
但需要注意的是:矩形右下角的值并不一定是baselinex+width!它的具體取值是跟paint.setTextAlign(Paint.Align.LEFT)有關的,因為我們這里設置為Paint.Align.LEFT,所以是baselinex+width。如果設置為Paint.Align.CENTER,那么右下角的X坐標值為baselinex+width/2;再者如果設置為Paint.Align.RIGHT,那么右下角的X坐標就是baselineX;所占矩形的四個角的所有位置是與paint.setTextAlign()的設置緊密相關的,至于各個點的計算方法就不再細講了,根據我們前面講的paint.setTextAlign()的顯示效果是非常容易想到的。
第三部分:畫最小區域矩形
//畫最小矩形
Rect minRect = new Rect();
paint.getTextBounds(text,0,text.length(),minRect);
minRect.top = baseLineY + minRect.top;
minRect.bottom = baseLineY + minRect.bottom;
paint.setColor(Color.RED);
canvas.drawRect(minRect,paint);
這部分也就沒什么難度了,首先根據paint.getTextBounds()得到基線為y=0的最小矩形的各點坐標,然后根據基線得到其實際的top和bottom坐標;然后將其畫出來即可
第四部分:畫文字
//畫文字
paint.setColor(Color.WHITE);
canvas.drawText(text, baseLineX, baseLineY, paint);
四、定點寫字
講完上面的三部分,這篇文章所要講的知識點基本就結束了,下面就是應用的部分了,在這部分中,我們將講述,當我們設定一個點,如何到得基線位置,進而畫出字符串。
1、給定左上頂點繪圖
這部分,我們假定給出所要繪制矩形的左上角頂點坐標,然后畫出這個文字。
先來看效果圖:
在這個圖中,我們給定左上角的位置,即(left,top);我們知道要畫文字,drawText()中傳進去的Y坐標是基線的位置,所以我們就必須根據top的位置計算出baseline的位置。
我們來看一個公式:
FontMetrics.top = top - baseline;
所以baseline = top - FontMetrics.top;
因為FontMetrics.top是可以得到的,又因為我們的top坐標是給定的,所以通過這個公式就能得到baseline的位置了。
下面舉個例子來說明一下根據矩形左上項點繪制文字的過程:
先看下效果圖:
在這個效果圖中,因為我們會給定矩形左上角頂點(left,top),所以們先畫出top線的位置,然后計算出baseline的位置,并畫出來。最后根據baseline把文字寫出來。
代碼如下:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String text = "matt's blog";
int top = 200;
int baseLineX = 0 ;
//設置paint
Paint paint = new Paint();
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
//畫top線
paint.setColor(Color.parseColor("#196F3D"));
canvas.drawLine(baseLineX, top, 2500, top, paint);
//計算出baseLine位置
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int baseLineY = top - fm.top;
//畫基線
paint.setColor(Color.parseColor("#FF0000"));
canvas.drawLine(baseLineX, baseLineY, 2500, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
canvas.drawText(text, baseLineX, baseLineY, paint);
}
這段代碼,比較簡單,首先是我們給定top給的位置int top = 200;然后根據top線位置計算出baseline所在位置,并畫出來.
2、給定中間線位置繪圖
先看效果圖:
在這個圖中,總共有四條線:top線,bottom線,baseline和center線;
圖中center線正是在top線和bottom線的正中間。
為了方便推導公式,我另外標了三個距離A,B,C;
很顯然,距離A和距離C是相等的,都等于文字所在矩形高度以的一半,即:
A = C = (bottom - top)/2;
又因為bottom = baseline + FontMetrics.bottom;
top = baseline+FontMetrics.top;
所以,將它們兩個代入上面的公式,就可得到:
A = C = (FontMetrics.bottom - FontMetrics.top)/2;
而距離B,則表示Center線到baseline的距離。
很顯然距離B = C - (bottom - baseline);
又因為
FontMetrics.bottom = bottom-baseline;
C = A;
所以,B = A - FontMetrics.bottom;
所以baseline = center + B = center + A - FontMetrics.bottom = center +
(FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom;
根據上面的推導過程,我們最終可知,當給定中間線center位置以后,baseline的位置為:
baseline = center + (FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom;
下面我們舉個例子來說明下這個公式的用法。
效果圖如下:
代碼如下:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String text = "matt's blog";
int center = 200;
int baseLineX = 0 ;
//設置paint
Paint paint = new Paint();
paint.setTextSize(120); //以px為單位
paint.setTextAlign(Paint.Align.LEFT);
//畫center線
paint.setColor(Color.parseColor("#1A5276"));
paint.setFakeBoldText(true);
paint.setStrokeWidth(3);
canvas.drawLine(baseLineX, center, 3000, center, paint);
//計算出baseLine位置
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int baseLineY = center + (fm.bottom - fm.top)/2 - fm.bottom;
//畫基線
paint.setColor(Color.parseColor("#FF0000"));
paint.setFakeBoldText(true);
paint.setStrokeWidth(3);
canvas.drawLine(baseLineX, baseLineY, 3000, baseLineY, paint);
//畫文字
paint.setColor(Color.BLUE);
canvas.drawText(text, baseLineX, baseLineY, paint);
}
這段代碼根據給定中間線的位置為200,然后計算出baseline的位置,然后把文字在baseline的基礎上畫出來。
公眾號:addapp