前言

笔者最近在做一款弹幕控件,里面涉及到绘制文本,以及文本边框。而绘制文本边框需要知道文本的左边位置,上边位置,以及文本的宽高。

通常来说,使用 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", 然后截图测量文本宽高,得出以下结果:

可以看到,文本的宽为 18, 高为 22。 可以得出以下结论:

方案1测量结果为近似值,存在一定误差。

方案3测量结果准确。

方案4测量结果精度更高,数值基本与方案3一致。

再多说几句。与测量文字高度类似,我们如何获取文字的基线 baseline 位置。

一般的博客上会告诉我们,如果需要计算文字的基线 baseline 位置,可以通过 FontMetrics 来计算。FontMetrics 基线上面的值为负数,基线下面的值为正数。baseline 计算公式为:

baseline = ascent + leading

如果你真的使用了这个公式就会发现坑。这个公式计算的基线位置实际上是默认字体的基线位置,与文字内容无关。我们可以看下面的例子:

在自定义 View 的 onDraw 方法中,绘制一个字符 "e", 绘制y坐标为 baseline,所以文字应该会顶着 Activity 的边界。

@Override

protected 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);

}

显示结果为:

那问题来了,究竟怎么计算才能计算出真实的文本的基线位置呢。

我们使用之前的方案3来试试。代码如下:

@Override

protected 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 显示了。

总结

精确测量文本宽高时,尽量不要使用 FontMetrics 去做。如果要求不精确,可以使用 Paint 的 measureText 方法计算文本宽度,如果要求精确测量,可以使用 Paint 的 getTextBounds 方法 或者 getTextPath 方法,获取文本的边界框矩形 Rect, 所获的Rect 的宽高即为文本的宽高, Rect的 top 为文本上边界距基线的距离, Rect 的 bottom 为文本下边距距离基线的距离。

本文涉及的代码可以在我的 GitHub 项目 AndroidBlogDemo github.com/hust2010107 (本地下载)… 。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

java精确测量文本高度_Android精确测量文本宽高及基线位置的方法相关推荐

  1. java设计一个立方体类box_实例1: 设计一个立方体类Box,定义三个属性,分别是长,宽,高。定义二个方法,分别计算并输出立方体的体积和表面积。_学小易找答案...

    [填空题]表达式 list(filter(lambda x:x>2, [0,1,2,3,0,0])) 的值为 _________ . [填空题]表达式 len(' 中国 '.encode('ut ...

  2. android 自定义view 高度,自定义View之宽高的设置,全网最详解

    今天给大家带来的是自定义View,然后如何设置他的宽高,经常用自定义view的程序猿肯定都知道我们在给自定义view设置wrap_content或者match_parent,view都会占满全屏,就想 ...

  3. java生成二维码,自定义宽高和边框大小

    下面封装的两个方法, url地址是http://开头的要不然浏览器没办法直接跳转 宽高都是一个数 wh 边框 margin 0是没有边框 ,1是最小边框 返回值 BufferedImage 类型的数据 ...

  4. android自定义view设置高度,自定义View的宽高设定

    关于View的属性 自定义动态设置View的大小属性 使用LayoutParams来设置view的宽高. int textLen = AddShopActivity.mCategoryItemName ...

  5. 页面宽高,窗口宽高,元素宽高,元素位置,页面滚动距离

    注:以下内容只适用于chrome 页面宽高: document.body.clientWidth/Height(不包括margin) document.body.offsetWidth/Height( ...

  6. java抢单功能_基于消息队列的高并发抢单功能实现方法与流程

    本发明涉及嵌入式软件中间件,具体涉及一种基于消息队列的高并发抢单功能实现方法. 背景技术: 中间件是一种独立的系统软件或服务程序,分布式应用系统借助这种软件在不同的技术之间共享资源,管理计算资源和网络 ...

  7. java精确测量文本高度_基于文本精确计算UITableViewCell的高度

    我正在开发一个ios应用程序,并使用autolayout我正在尝试创建一个具有不同行高的表视图 . 原型单元的布局如下: 我有一个主单元格(黑色)里面有一个UIView(红色),里面有一个UILabe ...

  8. 微信小程序 - 解决 rich-text 富文本解析图片无法自适应宽高问题(图片超出屏幕宽度且不受控)

    前言 注意:您无法通过直接指定 <img> 标签样式来试图设置为自适应图片. 使用官方 <rich-text> 富文本组件解析时, 当内容包含图片(大图)时显示的结果就会超出屏 ...

  9. java imageview的使用_Android使用控件ImageView加载图片的方法

    在 Android 加载图片一般使用 ImageView,这里简单记录一下这个控件的使用方法. 最简单就是在 xml 里直接使用 ImageView 标签: android:orientation=& ...

最新文章

  1. Ubuntu apt安装/卸载软件和设置软件源
  2. andiod 导入工程 报错
  3. matlab绘制三维图形
  4. 中国制造2025变革,背后的大数据来龙去脉
  5. iforums之UEditor上传图片提示【未知错误】
  6. Andromeda OS 来了,Android 再见?
  7. 《Spring Cloud》学习(一) 服务治理!
  8. 【Caffe安装】Ubuntu14.04上Caffe配置安装(Only CPU)
  9. 新中大账务软件win7连接慢的问题
  10. 2019大学生电子设计竞赛
  11. 创建对象的几种常用写法
  12. docker启动mysql报错Error starting userland proxy: listen tcp4 0.0.0.0:3306: bind: address already in use
  13. uni-app(微信小程序)连接HC系列蓝牙模块并进行双向通信采坑总结
  14. 實戰案例 - 資料對接工具程式碼重構 (2)
  15. STM32F103C8T6学习
  16. android ae动画教程,【博文精选】使用After Effects输出代码原生动画
  17. PAT甲级考纲(最少的时间换尽可能多的分数)
  18. sendfile详解
  19. java指针压缩临界值
  20. 十个鲜为人知的Linux命令-【4】

热门文章

  1. HP QC IE11不支持( win7 64位 无法安装)解决方法
  2. /dev、/sys/dev 和/sys/devices 和udev的关系
  3. php微服务架构设计模式,《微服务架构设计模式》读书笔记---第十一章:开发面向生产环境的微服务应用...
  4. python不带颜色的图形_如何使用Matplotlib设置图形背景颜色的不透明度 - python
  5. Spring中日期格式转换
  6. 在CentOS6.8下安装Docker
  7. JavaScript实现十种经典排序算法(js排序算法)
  8. 如何跟项目经理和开发人员反馈安全测试报告的问题
  9. WKWebView不显示提示框(Swift)
  10. 雷观(十六):帮人写项目,不如教会别人写项目的方法