国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android精確測量文本寬高及基線位置的方法

2019-10-21 21:41:35
字體:
來源:轉載
供稿:網友

前言

筆者最近在做一款彈幕控件,里面涉及到繪制文本,以及文本邊框。而繪制文本邊框需要知道文本的左邊位置,上邊位置,以及文本的寬高。

通常來說,使用 Canvas 繪制文本,可以通過畫筆 Paint 來設置文字的大小。但是畫筆的大小與文字的寬高并無直接關系。
大家應該能說上幾種測量文字寬高的方法,如:

方案1. 通過 Paint 的 measureText 方法,可以測量文字的寬度

方案2. 通過獲取 Paint 的 FontMetrics, 根據 FontMetrics 的 leading, ascent, 和 descent可以獲取文字的高度。

方案3. 通過 Paint 的 getTextBounds 獲取文本的邊界矩形 Rect,根據 Rect 可以計算出文字的寬高。

方案4. 通過 Paint 獲取文字的 Path, 根據 Path 獲取文本的邊界矩形 Rect, 根據 Rect 可以計算出文字的寬高。

表面上看,我們有以上四種方案可以獲取文字的寬或高。但是不幸的,這四種方案里,有些方法獲取到的數值不是真實的文字寬高。

我們通過以下測試代碼,分別測試字母 "e" 和 "j"。

private void measureText(String str) { if (str == null) {  return; } float width1 = mPaint.measureText(str); Log.i("lxc", "width1 ---> " + width1); Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); float height1 = Math.abs(fontMetrics.leading + fontMetrics.ascent) + fontMetrics.descent; Log.i("lxc", "height1 ---> " + height1); Rect rect = new Rect(); mPaint.getTextBounds(str, 0, str.length(), rect); float width2 = rect.width(); float height2 = rect.height(); Log.i("lxc", "width2 ---> " + width2); Log.i("lxc", "height2 ---> " + height2); Path textPath = new Path(); mPaint.getTextPath(str, 0, str.length(), 0.0f, 0.0f, textPath); RectF boundsPath = new RectF(); textPath.computeBounds(boundsPath, true); float width3 = boundsPath.width(); float height3 = boundsPath.height(); Log.i("lxc", "width3 ---> " + width3); Log.i("lxc", "height3 ---> " + height3);}

調用以下代碼測試

measureText("e");Log.i("lxc", " <----分割線----> ");measureText("j");

日志輸出如下:

08-13 22:50:20.777 4977-4977/com.orzangleli.textbounddemo I/lxc: width1 ---> 21.0
08-13 22:50:20.777 4977-4977/com.orzangleli.textbounddemo I/lxc: height1 ---> 46.875
08-13 22:50:20.777 4977-4977/com.orzangleli.textbounddemo I/lxc: width2 ---> 18.0
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: height2 ---> 22.0
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: width3 ---> 17.929688
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: height3 ---> 21.914062
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc:  <----分割線---->
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: width1 ---> 10.0
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: height1 ---> 46.875
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: width2 ---> 8.0
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: height2 ---> 37.0
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: width3 ---> 8.046875
08-13 22:50:20.778 4977-4977/com.orzangleli.textbounddemo I/lxc: height3 ---> 37.36328

首先,我們可以確定字母 "e" 和 "j" 的顯示高度應該不一樣,而使用第二種 FontMetrics 方案計算出的兩種情況文字高度一樣,而且從代碼的調用上看,我們也是直接根據 Paint 獲取的 FontMetrics, 與文字內容無關。所以我們需要測量文字真實高度的話,需要排除第二種方案了。

我們準備一個自定義 View,在 onDraw 方法中使用 mPaint 繪制一個文本 "e", 然后截圖測量文本寬高,得出以下結果:

Android,測量,文本寬高,基線位置

可以看到,文本的寬為 18, 高為 22。 可以得出以下結論:

方案1測量結果為近似值,存在一定誤差。

方案3測量結果準確。

方案4測量結果精度更高,數值基本與方案3一致。

再多說幾句。與測量文字高度類似,我們如何獲取文字的基線 baseline 位置。

Android,測量,文本寬高,基線位置

一般的博客上會告訴我們,如果需要計算文字的基線 baseline 位置,可以通過 FontMetrics 來計算。FontMetrics 基線上面的值為負數,基線下面的值為正數。baseline 計算公式為:

baseline = ascent + leading

如果你真的使用了這個公式就會發現坑。這個公式計算的基線位置實際上是默認字體的基線位置,與文字內容無關。我們可以看下面的例子:

在自定義 View 的 onDraw 方法中,繪制一個字符 "e", 繪制y坐標為 baseline,所以文字應該會頂著 Activity 的邊界。

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint.FontMetrics fontMetrics = mPaint.getFontMetrics(); float baseline = Math.abs(fontMetrics.leading + fontMetrics.ascent); canvas.drawText("e", 0, baseline, mPaint);}

顯示結果為:

Android,測量,文本寬高,基線位置

那問題來了,究竟怎么計算才能計算出真實的文本的基線位置呢。

我們使用之前的方案3來試試。代碼如下:

@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); String str = "e"; Rect rect = new Rect(); mPaint.getTextBounds(str, 0, str.length(), rect); float baseline = Math.abs(rect.top); canvas.drawText(str, 0, baseline, mPaint);}

看看效果, 已經能夠滿足我們的需求,左上都頂著 Activity 顯示了。

Android,測量,文本寬高,基線位置

總結

精確測量文本寬高時,盡量不要使用 FontMetrics 去做。如果要求不精確,可以使用 Paint 的 measureText 方法計算文本寬度,如果要求精確測量,可以使用 Paint 的 getTextBounds 方法 或者 getTextPath 方法,獲取文本的邊界框矩形 Rect, 所獲的Rect 的寬高即為文本的寬高, Rect的 top 為文本上邊界距基線的距離, Rect 的 bottom 為文本下邊距距離基線的距離。

本文涉及的代碼可以在我的 GitHub 項目 AndroidBlogDemo github.com/hust2010107 … 。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宝丰县| 枝江市| 中宁县| 苏尼特左旗| 衡山县| 汝州市| 潞西市| 上栗县| 福鼎市| 礼泉县| 文山县| 阿拉尔市| 莱阳市| 石狮市| 辽阳市| 石泉县| 嘉黎县| 新竹市| 松潘县| 泰安市| 綦江县| 肇源县| 唐山市| 正镶白旗| 通海县| 屏东市| 乌拉特中旗| 永寿县| 日喀则市| 临漳县| 宁蒗| 张家港市| 绥芬河市| 夏河县| 普安县| 木里| 秦安县| 安图县| 武城县| 永丰县| 南丰县|