溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

發(fā)布時間:2021-03-02 15:05:58 來源:億速云 閱讀:511 作者:戴恩恩 欄目:移動開發(fā)

這篇文章主要為大家詳細(xì)介紹了如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,發(fā)現(xiàn)的小伙伴們可以參考一下:

Android是什么

Android是一種基于Linux內(nèi)核的自由及開放源代碼的操作系統(tǒng),主要使用于移動設(shè)備,如智能手機(jī)和平板電腦,由美國Google公司和開放手機(jī)聯(lián)盟領(lǐng)導(dǎo)及開發(fā)。

首先把坐標(biāo)原點移動到控件中心(默認(rèn)坐標(biāo)原點在屏幕左上角),這樣看起來比較直觀一些,然后繪制x、y軸,此時原點向上y為負(fù),向下y為正,向左x為負(fù),向右x為正,以(0,0)坐標(biāo)開始繪制一段文本:

@Override
public void draw(Canvas canvas) {
 super.draw(canvas);
 // 將坐標(biāo)原點移到控件中心
 canvas.translate(getWidth() / 2, getHeight() / 2);
 // x軸
 canvas.drawLine(-getWidth() / 2, 0, getWidth() / 2, 0, paint);
 // y軸
 canvas.drawLine(0, -getHeight() / 2, 0, getHeight() / 2, paint);

 // 繪制文字
 paint.setTextSize(sp2px(50));
 canvas.drawText("YangLe", 0, 0, paint);
}

看下繪制的文本:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

繪制文本

咦,為什么繪制的文本在第一象限,y坐標(biāo)不是指定的0嗎,為什么文本沒有在x軸的上面或下面,而是穿過了x軸,帶著這些疑問繼續(xù)往下看:

首先看一個重要的類:

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;
}

FontMetrics類是Paint的一個內(nèi)部類,主要定義了繪制文本時的一些關(guān)鍵坐標(biāo)位置,看下這些值都代表什么:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

關(guān)鍵坐標(biāo)

看圖說話:

  • top:從基線(x軸)向上繪制區(qū)域的最高點,此值為負(fù)值

  • ascent:單行文本,從基線(x軸)向上繪制的推薦最高點,此值為負(fù)值

  • baseline:基線,此值為0

  • descent:單行文本,從基線(x軸)向下繪制的推薦最低點,此值為正值

  • bottom:從基線(x軸)向下繪制區(qū)域的最低點,此值為正值

  • leading:推薦的額外行距,一般為0

下面再來看看drawText這個方法:

/**
 * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted
 * based on the Align setting in the paint.
 *
 * @param text The text to be drawn
 * @param x The x-coordinate of the origin of the text being drawn
 * @param y The y-coordinate of the baseline of the text being drawn
 * @param paint The paint used for the text (e.g. color, size, style)
 */
public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
 super.drawText(text, x, y, paint);
}

重點看下x、y參數(shù)的含義:

  • x:繪制文本的起始x坐標(biāo)

  • y:繪制文本的baseline在y軸方向的位置

有點難理解,舉個栗子,上文中的x、y參數(shù)傳的是(0,0),此時的baseline正好是坐標(biāo)系中x軸,就相當(dāng)于從y軸開始向右繪制,以x軸作為文本的baseline進(jìn)行繪制。

如果參數(shù)傳(0,10),此時繪制文本的baseline從x軸開始向下移動10px,也就是以y10作為文本的baseline進(jìn)行繪制,y10就是繪制文本的baseline在y軸方向的位置。

注意:baseline是繪制文本的基線,相對于繪制文本區(qū)域來說,相當(dāng)于x軸,向上為負(fù)(top、ascent),向下為正(descent、bottom),但是這個x軸并不是控件的x軸,切記切記!??!

還記得我們在上文中提出的疑問嗎,這下可以解釋了:

為什么繪制的文本在第一象限?

因為我們把坐標(biāo)原點移到了控件中心,文本的baseline正好為x軸,top、ascent值為負(fù),所以繪制的文本在第一象限。

y坐標(biāo)不是指定的0嗎,為什么文本沒有在x軸的上面或下面,而是穿過了x軸?

drawText方法默認(rèn)x軸方向是從左到右繪制的,y軸方向是從baseline為基準(zhǔn)繪制的,文中的baseline正好為x軸,以baseline為基準(zhǔn)繪制文本向下還有一段距離,所以文本穿過了x軸。

3.繪制居中的文本

在上文中,我們學(xué)習(xí)了如何繪制一段文本,以及其中參數(shù)和坐標(biāo)的含義,接下來進(jìn)入正題,看下如何才能繪制居中的文本。

首先看一張圖,此時文本的baseline正好為x軸,如果想要文本居中顯示的話,就需要先計算文本的寬度和高度:

  • 寬度:調(diào)用Paint的measureText方法就可以獲得文本的寬度

  • 高度:文本的高度就是實際繪制區(qū)域的高度,可以用(fontMetrics.descent - fontMetrics.ascent)獲取,因為ascent為負(fù)數(shù),所以最終算出來的是兩者的和

現(xiàn)在有了寬度,把繪制文本的x坐標(biāo)向左移動(寬度 / 2)就可以水平居中,但是垂直方向就不能這么干了,我們要將文本向下移動baseline到文本中心的距離,也就是(高度 / 2 - fontMetrics.descent),如下圖所示:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

計算baseLineY

現(xiàn)在的公式為:

float baseLineY
= (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent;
= -fontMetrics.ascent / 2 - fontMetrics.descent / 2;
= -(fontMetrics.ascent + fontMetrics.descent) / 2;
= Math.abs(fontMetrics.ascent + fontMetrics.descent) / 2;

Paint中也有獲取ascent和descent值的方法,所以公式最終為:

float baseLineY = Math.abs(paint.ascent() + paint.descent()) / 2;

注意:此公式是相對于坐標(biāo)原點在控件中心來計算的,如果坐標(biāo)原點在左上角,baseLineY需要加上控件高度的一半。

float baseLineY = height / 2 + Math.abs(paint.ascent() + paint.descent()) / 2;

看下代碼:

@Override
public void draw(Canvas canvas) {
 super.draw(canvas);
 // 將坐標(biāo)原點移到控件中心
 canvas.translate(getWidth() / 2, getHeight() / 2);
 // x軸
 canvas.drawLine(-getWidth() / 2, 0, getWidth() / 2, 0, paint);
 // y軸
 canvas.drawLine(0, -getHeight() / 2, 0, getHeight() / 2, paint);

 // 繪制居中文字
 paint.setTextSize(sp2px(50));
 paint.setColor(Color.GRAY);
 // 文字寬
 float textWidth = paint.measureText("YangLe'Blog");
 // 文字baseline在y軸方向的位置
 float baseLineY = Math.abs(paint.ascent() + paint.descent()) / 2;
 canvas.drawText("YangLe'Blog", -textWidth / 2, baseLineY, paint);
}

看下居中了嗎:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

繪制居中文本

大功告成!

4.繪制多行居中的文本

注意:drawText方法不支持繪制多行文本

4.1 方式一

使用支持自動換行的StaticLayout:

/**
 * 繪制多行居中文本(方式1)
 *
 * @param canvas 畫布
 */
private void drawCenterMultiText1(Canvas canvas) {
 String text = "ABC";

 // 畫筆
 TextPaint textPaint = new TextPaint();
 textPaint.setAntiAlias(true);
 textPaint.setColor(Color.GRAY);

 // 設(shè)置寬度超過50dp時換行
 StaticLayout staticLayout = new StaticLayout(text, textPaint, dp2px(50),
  Layout.Alignment.ALIGN_CENTER, 1f, 0f, false);
 canvas.save();
 // StaticLayout默認(rèn)從(0,0)點開始繪制
 // 如果需要調(diào)整位置,只能在繪制之前移動Canvas的起始坐標(biāo)
 canvas.translate(-staticLayout.getWidth() / 2, -staticLayout.getHeight() / 2);
 staticLayout.draw(canvas);
 canvas.restore();
}

看下StaticLayout的構(gòu)造方法參數(shù)含義:

public StaticLayout(CharSequence source, TextPaint paint, int width, Alignment align, 
   float spacingmult, float spacingadd, boolean includepad) {
 this(source, 0, source.length(), paint, width, align, spacingmult, spacingadd, includepad);
}
  • source:需要分行的文本

  • paint:畫筆對象

  • width:layout的寬度,文本超出寬度時自動換行

  • align:layout的對其方式

  • spacingmult:相對行間距,相對字體大小,1f表示行間距為1倍的字體高度

  • spacingadd:基礎(chǔ)行距偏移值,實際行間距等于(spacingmult + spacingadd)

  • includepad:參數(shù)未知

看下效果:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

StaticLayout

使用StaticLayout,每行設(shè)置的寬度是相同的,當(dāng)需求為每行顯示不同長度的文本時,這種方式就不能使用了,別擔(dān)心,接著來看下第二種方式。

4.2 方式二

使用循環(huán)drawText的方式進(jìn)行繪制,看圖說話:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

計算baseLineY

現(xiàn)在需要繪制A、B、C三行文本,紅色A代表每行文本默認(rèn)的繪制位置,綠色的線代表每行文本的baseline,x軸為紅色A的baseline,現(xiàn)在分為三種情況:

  • 文本在x軸上方:紅色A的baseline向上移動a距離,總高度的/2 - 文本的top值(絕對值)

  • 文本在x軸中間:紅色A的baseline向下移動b距離,計算公式請參考單行文本居中公式

  • 文本在x軸下方:紅色A的baseline向下移動c距離,總高度的/2 - 文本的bottom值(絕對值)

看下代碼:

/**
 * 繪制多行居中文本(方式2)
 *
 * @param canvas 畫布
 */
private void drawCenterMultiText2(Canvas canvas) {
 String[] texts = {"A", "B", "C"};

 Paint.FontMetrics fontMetrics = paint.getFontMetrics();
 // top絕對值
 float top = Math.abs(fontMetrics.top);
 // ascent絕對值
 float ascent = Math.abs(fontMetrics.ascent);
 // descent,正值
 float descent = fontMetrics.descent;
 // bottom,正值
 float bottom = fontMetrics.bottom;
 // 行數(shù)
 int textLines = texts.length;
 // 文本高度
 float textHeight = top + bottom;
 // 文本總高度
 float textTotalHeight = textHeight * textLines;
 // 基數(shù)
 float basePosition = (textLines - 1) / 2f;

 for (int i = 0; i < textLines; i++) {
  // 文本寬度
  float textWidth = paint.measureText(texts[i]);
  // 文本baseline在y軸方向的位置
  float baselineY;

  if (i < basePosition) {
   // x軸上,值為負(fù)
   // 總高度的/2 - 已繪制的文本高度 - 文本的top值(絕對值)
   baselineY = -(textTotalHeight / 2 - textHeight * i - top);

  } else if (i > basePosition) {
   // x軸下,值為正
   // 總高度的/2 - 未繪制的文本高度 - 文本的bottom值(絕對值)
   baselineY = textTotalHeight / 2 - textHeight * (textLines - i - 1) - bottom;

  } else {
   // x軸中,值為正
   // 計算公式請參考單行文本居中公式
   baselineY = (ascent - descent) / 2;
  }

  canvas.drawText(texts[i], -textWidth / 2, baselineY, paint);
 }
}

對照上圖再看代碼就很好理解了,覺得代碼中的公式還有可以優(yōu)化的地方,如果你有好的方法,可以留言告訴我哈。
再看下中文版的多行文本:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

多行居中文本

TextAlign

Paint的TextAlign屬性決定了繪制文本相對于drawText方法中x參數(shù)的相對位置。
舉個栗子:

  • Paint.Align.LEFT:默認(rèn)屬性,x坐標(biāo)為繪制文本的最左側(cè)坐標(biāo)

  • Paint.Align.CENTER:x坐標(biāo)為繪制文本的水平中心坐標(biāo)

  • Paint.Align.RIGHT:x坐標(biāo)為繪制文本的最右側(cè)坐標(biāo)

看圖理解下:

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中

Paint.Align.LEFT

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中
Paint.Align.CENTER

如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中
Paint.Align.RIGHT

文本居中的公式

坐標(biāo)原點在控件中心:

float baseLineY = Math.abs(paint.ascent() + paint.descent()) / 2;

坐標(biāo)原點在控件左上角:

float baseLineY = height / 2 + Math.abs(paint.ascent() + paint.descent()) / 2;

以上就是億速云小編為大家收集整理的如何在Android中使用Canvas drawText屬性實現(xiàn)文字居中,如何覺得億速云網(wǎng)站的內(nèi)容還不錯,歡迎將億速云網(wǎng)站推薦給身邊好友。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI