Android自定義View之定點寫文字

前言:有經驗的Android開發者,應該都會遇到在自定義View的時候,在View的某個地方寫文字,那麼當你在自定義的View中寫文字的時候,可以作到定點寫文字嗎?可以指哪寫哪嗎?寫出來的文字的位置和本身想要的位置同樣嗎?即便你最後寫的文字的位置和本身想象的位置是同樣的,那麼你知道其中的原理嗎?若是其中有一個你不能回答出來,那就認真的閱讀本文吧!本文會給出你想要的答案...java

一個小例子

  看下下面的圖,假以下面的圖是咱們要作出的效果canvas

很簡單,有沒有?就是在一個圓的中心寫文字。紅色的圓形很好畫出來,那麼咱們怎麼將文字寫在圓的中心點上呢?第一時間想到的是拿到圓中心點的座標,而後直接調用drawText()方法來寫文字。實現的代碼大體以下ide

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int measuredHeight = getMeasuredHeight();
        int measuredWidth = getMeasuredWidth();

        //cx,cy爲圓的中心點的座標
        int cx = measuredWidth / 2;
        int cy = measuredHeight / 2;
        canvas.drawCircle(cx, cy, mRadius, mPaint);
        mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
        mPaint.setColor(Color.WHITE);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(getResources().getDimensionPixelSize(R.dimen.dp1));
        canvas.drawText("wizardev", cx, cy, mPaint);
        
    }
複製代碼

如今,看下上面代碼實現的效果spa

上圖中的黃線是在圓的中心點畫的線,能夠發現上面代碼實現的效果,明顯不是咱們想要的效果,爲何會這樣呢?下文會給出答案。code

drawText()中的基線

  在Android中自定義View的時候,怎麼讓系統知道應該在哪裏畫出咱們想要的圖形呢?好比畫上面的圓,這時咱們就要告訴系統,咱們要畫的圓形的圓心在什麼位置,告訴系統咱們想要的圓的半徑是多少,而後系統就能在合適的位置畫出你想要的圓了。一樣,在畫文字的時候咱們要指定文字在什麼位置,而指定的座標的位置就是文字的基線。cdn

  要理解drawText()中的基線是什麼,須要先了解一下darwText()方法,darwText()方法有四個參數,以下對象

drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
複製代碼

第一個參數爲你想要寫的內容,第二個參數爲文字開始的X軸座標,第三個參數爲文字開始的Y軸座標,第四個參數爲畫筆。以第二個第三個參數畫的一條水平線,就是drawText()的基線。如上文中的第二張圖,黃色的線即爲drawText()基線,blog

注:第二和第三個參數不必定爲文字開始的座標,也可能爲文字中心的座標或則文字結尾的座標,具體是哪一種座標與Paint中的setTextAlign()方法有關。開發

  能夠得出結論,只要肯定了基線的位置就肯定了要畫的文字的位置了。那麼給定一個座標,怎麼肯定基線的位置呢?其實畫文字的時候,除了基線之外,還有其餘幾條線,其餘幾條線的位置以下圖get

這幾條線的意義分別是:

  • ascent: 系統建議的,字符所佔的最高高度所在線
  • descent:系統建議的,字符所佔的最低高度所在線
  • top: 可繪製的最高高度所在線
  • bottom: 可繪製的最低高度所在線

這幾條線的位置能夠經過FontMetrics對象得到。

FontMetrics

(1)FontMetrics概述

  描述給定文本的各類度量值的類,它有五個成員變量,分別爲topascentdescentbottomleading。這幾個成員變量的值都是相對基線位置的距離,如:

FontMetrics.top = top的Y座標 - 基線

(2)獲取FontMetrics對象

想要獲取FontMetrics,能夠經過getFontMetrics()方法獲取,具體代碼以下

Paint mPaint = new Paint()
mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
mPaint.setColor(Color.WHITE);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setStrokeWidth(1);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
複製代碼

(3)FontMetrics注意事項

  使用FontMetrics獲取到的topascentdescentbottomleading成員變量的值,是相對於基線的距離,並非座標,能夠看下下圖,方便理解

能夠發現topascent的值爲負數,descentbottom的值爲正數,爲何會這樣呢?由於top線和ascent線在基線的上方,FontMetrics對象中的幾個成員變量的值都是表示相對基線的位置。

指定位置寫文字

  瞭解了FontMetrics再結合下圖

能夠獲得下面的公式:

  • top的Y座標 = 基線 + fontMetrics.top
  • ascent的Y座標 = 基線 + fontMetrics.ascent
  • decent的Y座標 = 基線 + fontMetrics.descent
  • bottom的Y座標 = 基線 + fontMetrics.bottom

(1)給定左上方點寫字

根據得出的公式能夠計算出基線的Y座標

top的Y座標 = 基線 + fontMetrics.top

基線 = top的Y座標 - fontMetrics.top

實現的代碼以下

Paint mPaint = new Paint();
mPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.sp18));
mPaint.setStrokeWidth(1);
mPaint.setColor(Color.RED);
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
float baseLine = cy-fontMetrics.top;//cy指定點的Y座標
canvas.drawText("wizardev", 0, baseLine, mPaint);

複製代碼

(2)給定中間線寫文字

給定中間線寫文字,能夠說是自定義view寫文字時用的最多的了,如,將文字寫在圓的正中間,如上圖,圓的中心線將文字平分,這種就是本文說的給定中間線寫文字。文章前面說了,只要肯定了基線的位置,文字的位置也就肯定了,那麼像這種,怎樣來肯定基線的位置呢?這時咱們能夠藉助其餘的幾條線來計算出基線的位置。

如上圖,將topcenter之間的間距設爲A,將centerbaseline之間的距離設爲B,將centerbottom之間的距離設爲C。這是就能夠得出下面的公式

A = C = (bottom - top)/2

B = baseline - center

B = C - (bottom - baseline )

而後根據上文獲得的公式:

bottom = fontMetrics.bottom + baseline

top = fontMetrics.top + baseline

能夠將最上面的公式修改成:

baseline - center = (fontMetrics.bottom + baseline - fontMetrics.top - baseline) / 2 - (fontMetrics.bottom + baseline - baseline)

最後的到的公式爲:

baseline = center - (fontMetrics.bottom - fontMetrics.top) / 2 + fontMetrics.bottom

上面的到的公式就是給出中心線的位置,最後計算出的基線所在位置的公式。

(3)給定底部線線文字

  這種狀況應該是最簡單的了,直接把給定點的Y座標做爲基線的Y座標就好了。

結束語

  文章到這裏,已經回答了文章開始的幾個問題,相信閱讀本文以後,你也對自定義View中畫文字有了更清晰的理解。若是仍有什麼疑問,能夠在文章下方留言。

本文已由公衆號「AndroidShared」首發

歡迎關注個人公衆號
掃碼關注公衆號,回覆「獲取資料」有驚喜
相關文章
相關標籤/搜索