使用canvas與Paint在View中置中繪製文字,canvaspaint

來源:互聯網
上載者:User

使用canvas與Paint在View中置中繪製文字,canvaspaint

本部落格只要沒有註明“轉”,那麼均為原創,轉貼請註明本部落格網站連結接

 

我們在自訂View中有的時候會想自己繪製文字,自己繪製文字的時候,我們通常希望把文字精確定位,文字置中(水平、垂直)是普遍的需求,所以這裡就以文字置中為例,看一下android中的文字應該如何繪製,它與Java又有什麼區別。

先來看看我們的目標,見

是我開啟了“顯示布局邊界”後截的圖,所有會有好多框框。

仔細觀察文字地區,我們會發現文字地區中有5條顏色不同的線。按著從上到下的順序,他們的名字分別是:

top:淺灰色

ascent:黃色

baseline:紅色

descent:藍色

bottom:綠色

 

這5條線到底是什嗎?android開發文檔中已經進行瞭解釋。

top The maximum distance above the baseline for the tallest glyph in the font at a given text size.
ascent The recommended distance above the baseline for singled spaced text.
leading The recommended additional space to add between lines of text.
descent The recommended distance below the baseline for singled spaced text.
bottom The maximum distance below the baseline for the lowest glyph in the font at a given text size.

我們先稍微跑一下題

如果你嘗試過將兩個TextView上下排列,沒有margin和padding,那麼你一定會發現,兩個TextView文字之間依然是有空隙的。首先我們需要設定includeFontPadding為false!但是依然有空隙,這時的空隙就是由top與ascent之間的空隙和bottom與descent直接的空隙造成的了。

 

那5條線的位置是由使用的字型和字型大小決定的。Paint提供了擷取上面5條線位置的方法。

一般情況下,我們使用的字元是在ascent與descent之間的,所以我們讓ascent與descent之間的部分相對我們的View置中即可。

以baseline為基準,向上為負,向下為正。ascent為負數,descent為正數。

Canvas中的drawText中的總座標是baseline,所以我們這裡要先算出baseline的位置才行。

baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent

使得ascent到View的是上邊距與descent到View下邊距距離一致即可,此段距離加上ascent的絕對值(-ascent)即為baseline的位置

private void init() {    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    mPaint.setStrokeWidth(3);    mPaint.setTextSize(60);    mPaint.setTextAlign(Paint.Align.CENTER);    mPaint.setStyle(Paint.Style.STROKE);    mFontMetricsInt = mPaint.getFontMetricsInt();}@Overridepublic void onDraw(Canvas canvas) {    int x;    if (mPaint.getTextAlign() == Paint.Align.LEFT) { //左        x = mWidth / 2 - (int) (mStringWidth / 2);    } else if (mPaint.getTextAlign() == Paint.Align.CENTER) { //中        x = mWidth / 2;    } else { //右        x = mWidth / 2 + (int) (mStringWidth / 2);    }    int xFrom = mWidth / 2 - (int) (mStringWidth / 2);    int xTo = mWidth / 2 + (int) (mStringWidth / 2);    // baseline = (mHeight - (mFontMetricsInt.descent - mFontMetricsInt.ascent)) / 2 - mFontMetricsInt.ascent    // baseline = (mHeight - mFontMetricsInt.ascent - mFontMetricsInt.descent) / 2    int y = (mHeight - mFontMetricsInt.ascent - mFontMetricsInt.descent) / 2;    Log.d(TAG, "ascent: " + mFontMetricsInt.ascent);    Log.d(TAG, "descent: " + mFontMetricsInt.descent);    Log.d(TAG, "top: " + mFontMetricsInt.top);    Log.d(TAG, "bottom: " + mFontMetricsInt.bottom);    Log.d(TAG, "baseline: " + y);    // baseline    mPaint.setColor(Color.RED);    canvas.drawLine(xFrom, y, xTo, y, mPaint);    // ascent    mPaint.setColor(Color.YELLOW);    canvas.drawLine(xFrom, y + mFontMetricsInt.ascent, xTo, y + mFontMetricsInt.ascent, mPaint);    // descent    mPaint.setColor(Color.BLUE);    canvas.drawLine(xFrom, y + mFontMetricsInt.descent, xTo, y + mFontMetricsInt.descent, mPaint);    // top    mPaint.setColor(Color.LTGRAY);    canvas.drawLine(xFrom, y + mFontMetricsInt.top, xTo, y + mFontMetricsInt.top, mPaint);    // bottom    mPaint.setColor(Color.GREEN);    canvas.drawLine(xFrom, y + mFontMetricsInt.bottom, xTo, y + mFontMetricsInt.bottom, mPaint);    mPaint.setColor(Color.BLACK);    canvas.drawText(TEST_STRING, x, y, mPaint);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    mWidth = w;    mHeight = h;}private int mWidth;private int mHeight;private float mStringWidth;private float measureText() {    mStringWidth = mPaint.measureText(TEST_STRING);    return mStringWidth;}

注意:上面的那幾條線的位置和字型是有關的,比如,當你使用“方正姚體”的時候,會發現top和ascent重合了

private void init() {    mTf = Typeface.createFromAsset(mContext.getAssets(), "fzyt.ttf");    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    mPaint.setTypeface(mTf);    mPaint.setStrokeWidth(3);    mPaint.setTextSize(60);    mPaint.setTextAlign(Paint.Align.CENTER);    mPaint.setStyle(Paint.Style.STROKE);  // 畫空心矩形    mFontMetricsInt = mPaint.getFontMetricsInt();    Log.d(TAG, "measureText: " + measureText());}

垂直置中解決了,水平置中就容易了。因為……可以在Paint中直接設定。

mPaint.setTextAlign(Paint.Align.CENTER);

當然,這裡的對其方式只有左中右,即使這裡沒有設定置中,我們也是可以手動置中文字的。

int x;if (mPaint.getTextAlign() == Paint.Align.LEFT) { //左    x = mWidth / 2 - (int) (mStringWidth / 2);} else if (mPaint.getTextAlign() == Paint.Align.CENTER) { //中    x = mWidth / 2;} else { //右    x = mWidth / 2 + (int) (mStringWidth / 2);}

橫縱座標計算好了之後,我們就可以drawText了。

canvas.drawText(TEST_STRING, x, y, mPaint);

至此,問題全部解決,我們知道文字上面的那幾條線的位置,就能隨意放置我們的文字了。

繪製數位時候,1明顯比4瘦,但是我們可能會得到他們寬度相同的結果,也就沒有辦法“真正的置中”了。

附上layout檔案,如果你設定了padding,記得把padding也計算進去。

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:orientation="vertical"              android:layout_width="fill_parent"              android:layout_height="fill_parent"        android:background="#FFFFFF">    <com.example.TextTest.TextView            android:layout_width="250dip"            android:layout_height="100dip"            android:layout_marginTop="10dip"            android:layout_marginBottom="20dip"            android:layout_marginLeft="10dip"            android:layout_marginRight="20dip"/></LinearLayout>

 

最後我們來看看Java中的字型和Android的區別。

Java中字型的概念在這裡:Font Concepts。可以看到,這裡並沒有Android中的top和bottom的概念。

在維基百科中也有baseline相關解釋。這裡也是沒有提到Android中的top與bottom的概念

 

 

轉貼請保留以下連結

本人blog地址

http://su1216.iteye.com/

http://blog.csdn.net/su1216/

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.