Android自定義View之定點寫文字

wizardev發表於2018-07-31

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

一個小例子

  看下下面的圖,假如下面的圖是我們要做出的效果

Android自定義View之定點寫文字

很簡單,有沒有?就是在一個圓的中心寫文字。紅色的圓形很好畫出來,那麼我們怎麼將文字寫在圓的中心點上呢?第一時間想到的是拿到圓中心點的座標,然後直接呼叫drawText()方法來寫文字。實現的程式碼大致如下

  @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);
        
    }
複製程式碼

現在,看下上面程式碼實現的效果

Android自定義View之定點寫文字

上圖中的黃線是在圓的中心點畫的線,可以發現上面程式碼實現的效果,明顯不是我們想要的效果,為什麼會這樣呢?下文會給出答案。

drawText()中的基線

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

  要理解drawText()中的基線是什麼,需要先了解一下darwText()方法,darwText()方法有四個引數,如下

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

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

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

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

Android自定義View之定點寫文字

這幾條線的意義分別是:

  • 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成員變數的值,是相對於基線的距離,並不是座標,可以看下下圖,方便理解

Android自定義View之定點寫文字

可以發現topascent的值為負數,descentbottom的值為正數,為什麼會這樣呢?因為top線和ascent線在基線的上方,FontMetrics物件中的幾個成員變數的值都是表示相對基線的位置。

指定位置寫文字

  瞭解了FontMetrics再結合下圖

Android自定義View之定點寫文字

可以得到下面的公式:

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

(1)給定左上方點寫字

Android自定義View之定點寫文字

根據得出的公式可以計算出基線的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)給定中間線寫文字

Android自定義View之定點寫文字

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

Android自定義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”首發

歡迎關注我的公眾號
掃碼關注公眾號,回覆“獲取資料”有驚喜

相關文章