Android——自定義View——文字繪制

HenCoder Android 開發(fā)進(jìn)階:自定義 View 1-3 文字的繪制

一激才、作用

二取具、概念

1. API

(1)drawText()

// 將字符串[start,end)范圍內(nèi)的字符繪制出來毕箍,繪制起點(diǎn)(x,y)
public void drawText (CharSequence text, int start, int end, float x, float y, Paint paint)

(2)drawTextOnPath()

// 將指定字符沿 path 繪制
public void drawTextOnPath (char[] text, int index,  int count, Path path, float hOffset, float vOffset, Paint paint)

(3)drawTextRun()

2. 術(shù)語

(1)基線

(2)行間距倍數(shù)
Android TextView行間距解析

(3)行間距額外增加值

行間距倍數(shù)、行間距額外增加值改變了文字占用的高度肮帐,從而在視覺上形成了行與行之間間隔的效果。

public int getLineHeight() {
    return FastMath.round(mTextPaint.getFontMetricsInt(null) * mSpacingMult + mSpacingAdd);
}

(4)和文字繪制相關(guān)的5條線

摘自 扔物線

  • leading

上行的bottom和下行的top線距離捍掺。

3. StaticLayout

(1)作用
Canvas::drawText()繪制文字時(shí)不能換行:文字不能在 View 邊緣自動(dòng)換行;不能在\n處換行

StaticLayout繪制文字時(shí)能換行:文字在 View 邊緣自動(dòng)換行再膳;在\n處換行

(2)構(gòu)造函數(shù)

StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includedpad)
// spacingmult :行間距倍數(shù)挺勿,通常情況下填1就好
// spacingadd:行間距額外增加的數(shù)值,通常情況下填0就好
// includedpad:是指是否在文字上下添加額外的空間喂柒,來避免某些過高的字符的繪制出現(xiàn)越界

4. Paint 對(duì)文字繪制的輔助能力

(1)對(duì)文字繪制的輔助

(2)測(cè)量文字尺寸類

  • float getFontSpacing()

獲取推薦的行間距不瓶,即兩行文字的baseline的距離。這個(gè)值是系統(tǒng)根據(jù)文字的字體和字號(hào)自動(dòng)計(jì)算的灾杰。

當(dāng)你需手動(dòng)繪制多行文字(而不是使用StaticLayout時(shí))蚊丐,可以在換行的時(shí)候給y坐標(biāo)加上這個(gè)值來下移文字。

  • FontMetrics getFontMetrics()

提供幾個(gè)文字排版方面的數(shù)值艳吠。

從定義可得麦备,兩行文字的 font spacing(即兩行文字的baseline的距離),可以通過bottom-top+leading計(jì)算得出昭娩。

但實(shí)際上bottom-top+leading的結(jié)果要大于getFontSpacing()返回的值凛篙。因?yàn)椋?code>getFontSpacing()不是通過FontMetric的標(biāo)準(zhǔn)值計(jì)算出來的,而是另外計(jì)算出來的一個(gè)值栏渺,它能夠做到在兩行文字不顯得擁擠的前提下縮短行距呛梆,以此來得到更好的顯示效果。

所以:如果你需要對(duì)文字手動(dòng)換行繪制磕诊,多數(shù)時(shí)候應(yīng)該選取getFontSpacing()來得到行距填物,不但使用簡(jiǎn)單,顯示效果也更好秀仲。

  • void getTextBounds(CharSequence text, int start, int end, Rect bounds)

測(cè)量文字顯示范圍

// text:要測(cè)量的文字
// start:起始位置
// end:結(jié)束位置
// bounds:存儲(chǔ)文字顯示范圍融痛,該方法測(cè)量完后將數(shù)值存儲(chǔ)在該對(duì)象中
  • float measureText(CharSequence text, int start, int end)

測(cè)量文字寬度并返回

// text:要測(cè)量的文字
// start:起始位置
// end:結(jié)束位置
  • void getTextWidth(String text, int start, int end, int[] widths)

測(cè)量字符串中每個(gè)字符的寬度壶笼,并將結(jié)果填充到數(shù)組中

  • int breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth)

根據(jù)傳入的 maxWidth神僵,測(cè)量出能顯示的最大字符個(gè)數(shù),并返回

三覆劈、使用

HenCoder 的練習(xí)做完啦

1.measureText()

效果
float text1Width = paint1.measureText(text1);
float text2Width = paint2.measureText(text2);

canvas.drawText(text1, 50, 200, paint1);
canvas.drawText(text2, 50 + text1Width, 200, paint2);
canvas.drawText(text3, 50 + text1Width + text2Width, 200, paint1);

2.getTextBounds()

效果

結(jié)合getTextBounds方法簡(jiǎn)析繪制文字時(shí)需要注意的地方
getTextBounds中bounds的坐標(biāo)原點(diǎn)

這種居中算法的優(yōu)點(diǎn)是保礼,可以讓文字精準(zhǔn)地居中,分毫不差

摘自"結(jié)合getTextBounds方法簡(jiǎn)析繪制文字時(shí)需要注意的地方"

打印A责语、j炮障,分別調(diào)用getTextBounds()返回的結(jié)果

A::top=-114,bot=0,left=2,right=103
j::top=-116,bot=35,left=-6,right=28
  • 使用 Paint.getTextBounds() 計(jì)算出文字的顯示區(qū)域
Rect textBounds = new Rect();
paint2.getTextBounds(text, 0, texts.length(), textBounds);
  • 計(jì)算出文字的baseliney坐標(biāo)相對(duì) middle 的偏移量
yOffsets = - (textBounds.top + textBounds.bottom) / 2;
  • 繪制文字,讓文字在框中上下居中
canvas.drawRect(50, top, getWidth() - 50, bottom, paint1);
int middle = (top + bottom) / 2;
canvas.drawText(texts, 100, middle + yOffsets, paint2);

3.getFontMetrics()

效果
  • 使用 Paint.getFontMetrics() 得到acent坤候、decent
Paint.FontMetrics fontMetrics = paint2.getFontMetrics();
  • 計(jì)算出文字的baseliney坐標(biāo)相對(duì) middle 的偏移量(計(jì)算邏輯同上)
yOffset = - (fontMetrics.ascent + fontMetrics.descent) / 2;
  • 繪制文字胁赢,讓文字在框中上下居中
canvas.drawRect(50, top, getWidth() - 50, bottom, paint1);
int middle = (top + bottom) / 2;
canvas.drawText(text, 100, middle + yOffset, paint2);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市白筹,隨后出現(xiàn)的幾起案子智末,更是在濱河造成了極大的恐慌谅摄,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件系馆,死亡現(xiàn)場(chǎng)離奇詭異送漠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)由蘑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門闽寡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尼酿,你說我怎么就攤上這事爷狈。” “怎么了裳擎?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵淆院,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我句惯,道長(zhǎng)土辩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任抢野,我火速辦了婚禮拷淘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘指孤。我一直安慰自己启涯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布恃轩。 她就那樣靜靜地躺著结洼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叉跛。 梳的紋絲不亂的頭發(fā)上松忍,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音筷厘,去河邊找鬼鸣峭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛酥艳,可吹牛的內(nèi)容都是我干的摊溶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼充石,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼莫换!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤溃列,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膛薛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體听隐,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年哄啄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雅任。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咨跌,死狀恐怖沪么,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锌半,我是刑警寧澤禽车,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站刊殉,受9級(jí)特大地震影響殉摔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜记焊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一逸月、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧遍膜,春花似錦碗硬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挽懦,卻和暖如春翰意,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巾兆。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工猎物, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留虎囚,地道東北人角塑。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像淘讥,于是被迫代替她去往敵國(guó)和親圃伶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353