java精确测量文本高度_Android精确测量文本宽高及基线位置的方法
前言
笔者最近在做一款弹幕控件,里面涉及到绘制文本,以及文本边框。而绘制文本边框需要知道文本的左边位置,上边位置,以及文本的宽高。
通常来说,使用 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精确测量文本宽高及基线位置的方法相关推荐
- java设计一个立方体类box_实例1: 设计一个立方体类Box,定义三个属性,分别是长,宽,高。定义二个方法,分别计算并输出立方体的体积和表面积。_学小易找答案...
[填空题]表达式 list(filter(lambda x:x>2, [0,1,2,3,0,0])) 的值为 _________ . [填空题]表达式 len(' 中国 '.encode('ut ...
- android 自定义view 高度,自定义View之宽高的设置,全网最详解
今天给大家带来的是自定义View,然后如何设置他的宽高,经常用自定义view的程序猿肯定都知道我们在给自定义view设置wrap_content或者match_parent,view都会占满全屏,就想 ...
- java生成二维码,自定义宽高和边框大小
下面封装的两个方法, url地址是http://开头的要不然浏览器没办法直接跳转 宽高都是一个数 wh 边框 margin 0是没有边框 ,1是最小边框 返回值 BufferedImage 类型的数据 ...
- android自定义view设置高度,自定义View的宽高设定
关于View的属性 自定义动态设置View的大小属性 使用LayoutParams来设置view的宽高. int textLen = AddShopActivity.mCategoryItemName ...
- 页面宽高,窗口宽高,元素宽高,元素位置,页面滚动距离
注:以下内容只适用于chrome 页面宽高: document.body.clientWidth/Height(不包括margin) document.body.offsetWidth/Height( ...
- java抢单功能_基于消息队列的高并发抢单功能实现方法与流程
本发明涉及嵌入式软件中间件,具体涉及一种基于消息队列的高并发抢单功能实现方法. 背景技术: 中间件是一种独立的系统软件或服务程序,分布式应用系统借助这种软件在不同的技术之间共享资源,管理计算资源和网络 ...
- java精确测量文本高度_基于文本精确计算UITableViewCell的高度
我正在开发一个ios应用程序,并使用autolayout我正在尝试创建一个具有不同行高的表视图 . 原型单元的布局如下: 我有一个主单元格(黑色)里面有一个UIView(红色),里面有一个UILabe ...
- 微信小程序 - 解决 rich-text 富文本解析图片无法自适应宽高问题(图片超出屏幕宽度且不受控)
前言 注意:您无法通过直接指定 <img> 标签样式来试图设置为自适应图片. 使用官方 <rich-text> 富文本组件解析时, 当内容包含图片(大图)时显示的结果就会超出屏 ...
- java imageview的使用_Android使用控件ImageView加载图片的方法
在 Android 加载图片一般使用 ImageView,这里简单记录一下这个控件的使用方法. 最简单就是在 xml 里直接使用 ImageView 标签: android:orientation=& ...
最新文章
- Ubuntu apt安装/卸载软件和设置软件源
- andiod 导入工程 报错
- matlab绘制三维图形
- 中国制造2025变革,背后的大数据来龙去脉
- iforums之UEditor上传图片提示【未知错误】
- Andromeda OS 来了,Android 再见?
- 《Spring Cloud》学习(一) 服务治理!
- 【Caffe安装】Ubuntu14.04上Caffe配置安装(Only CPU)
- 新中大账务软件win7连接慢的问题
- 2019大学生电子设计竞赛
- 创建对象的几种常用写法
- docker启动mysql报错Error starting userland proxy: listen tcp4 0.0.0.0:3306: bind: address already in use
- uni-app(微信小程序)连接HC系列蓝牙模块并进行双向通信采坑总结
- 實戰案例 - 資料對接工具程式碼重構 (2)
- STM32F103C8T6学习
- android ae动画教程,【博文精选】使用After Effects输出代码原生动画
- PAT甲级考纲(最少的时间换尽可能多的分数)
- sendfile详解
- java指针压缩临界值
- 十个鲜为人知的Linux命令-【4】
热门文章
- HP QC IE11不支持( win7 64位 无法安装)解决方法
- /dev、/sys/dev 和/sys/devices 和udev的关系
- php微服务架构设计模式,《微服务架构设计模式》读书笔记---第十一章:开发面向生产环境的微服务应用...
- python不带颜色的图形_如何使用Matplotlib设置图形背景颜色的不透明度 - python
- Spring中日期格式转换
- 在CentOS6.8下安装Docker
- JavaScript实现十种经典排序算法(js排序算法)
- 如何跟项目经理和开发人员反馈安全测试报告的问题
- WKWebView不显示提示框(Swift)
- 雷观(十六):帮人写项目,不如教会别人写项目的方法