Android自定义View之文字居中
前言
本文讲文字的居中,不过在你阅读本文之前,强烈建议你读一下我的上一篇文章Android自定义View之DashBoard(仪表盘) ,因为上一篇的内容讲了Paint和Canvas等基础绘制的知识,你学会上一篇的内容再看现在的这篇会容易的多。看了文章题目,你会发现本文只讲一个点,就是文字居中,可能你会觉得就一个文字居中有必要单独拿一篇文章来讲吗?一开始我自己觉得没必要,后来发现有很多工作3、4年的Android开发者都没弄明白到底该怎么使文字居中,所以就有了这篇文章。关于文字居中,我保证你认真看了我的这篇文章,你一定能彻彻底底地明白如何去做。
文字居中
我们先来回忆一下绘制文字的方法:
drawText(String text, float x, float y, Paint paint)
方法的参数很简单: text 是文字内容,x 和 y 是文字的坐标。但需要注意:这个坐标并不是文字的左上角,而是一个与左下角比较接近的位置。大概在这里:
注意要特别强调一下y(也就是纵坐标)是 基线的位置,这时候你一定会问啥事基线,长什么样啊,接着看图
为什么会要用基线?这是因为每个字符的长度不太一样,比如我图中的例子,“a"、“b”和“g”这三个字符的长度明显不一样,我们没有办法简单的顶部对齐或者底部对齐,所以我们需要这么一个东西来让文字的重心对齐,这样会给用户一个更好的视觉效果。知道了文字绘制基线的概念,那么如果我们在(0,0)位置(原点)绘制一下"abcdefg"会怎么样呢?
放心,你没有看错,因为我刚才说了y坐标指的是文字基线的位置,基线的位置在“0”坐标,那么绘制的东西自然是在坐标系以外也就是我们看不见的地方了。
只有明白了基线的概念,我们才能继续讲如何居中。
关于文字居中,其实水平方向居中,非常简单,只需要一行代码
mPaint.setTextAlign(Paint.Align.CENTER);//Paint设置水平居中
下面我们先不管竖直居中的问题,先在(getWidth()/2,getHeight()/2)View的中心点,绘制一下文字
怎么样?是不是感觉有那么一点不对劲的地方(为了看得更明显我在外面加了一个圈),文字有一点“偏上”的赶脚。没错,这都是因为基线惹的祸,刚才说了y坐标是基线的位置,也就是说,文字的基线在竖直居中的位置,而文字的正中心则并没有做到竖直居中,明显是有一个偏移量的。重点来了,如何计算这个偏移量呢?
有两种方式
第一种 通过Paint.getTextBounds()方法
先讲一下方法
- getTextBounds(String text, int start, int end, Rect bounds)
参数里,text 是要测量的文字,start 和 end 分别是文字的起始和结束位置,bounds 是存储文字显示范围的对象,方法在测算完成之后会把结果写进 bounds
知道了方法怎么用,我就先简单地讲一下思路,通过getTextBounds获得文字的边框Bounds,然后通过Bounds.top+Bounds.bottom/2,这个就是偏移量,最后减去就可以了,不多说,直接上代码
Rect bounds=new Rect(); String text="abcdefg"; mPaint.getTextBounds(text,0,text.length(),bounds); float offSet=(bounds.top+bounds.bottom)/2; canvas.drawText("text",centerX,centerY-offSet,mPaint);
再看一眼效果图
问题来了,这里为什么是bounds.top+bounds.bottom,而不是bounds.bottom-bounds.top?最后为什么要减掉偏移量?
首先,调用getTextBounds()方法会在文字形成一个边框,同时还会形成一个坐标系(如图中绿色所画),正是在这个坐标系下,top是负值,bottom是负值,你可以把这两个值理解为向量,之所以是(bounds.top+bounds.bottom)/2,因为我们要算得是文字的 中间位置,而不是文字的高度的一半,之所以要减去,就像图中标注的一样,我们现在要把文字向 下移动,而中间位置的方法是负,也就是向 上,方向相反,所以要减去偏移量,我们再从数学的角度分析一下,减去一个负值,相当于加上一个正值,因此,是会把文字向下移动的,这样,文字就居中了。
第二种 通过FontMetircs
获取FontMetircs的方法:
FontMetrics 是个相对专业的工具类,它提供了几个文字排印方面的数值:ascent, descent, top, bottom, leading
ascent和descent分别代表了普通文字的顶部和底部,而top和bottom则代表了所有字符的顶部和底部,有些特殊字符可能会超过ascent和descent,但永远不会超过top和bottom
下面我还是画个图来描述一下吧
图中内部的两条线分别是ascent和descent,外部是top和bottom。
注意,这几条线是FontMetrics规定好的,也就是说这四个值是 固定不变 的,无论你绘制的内容如何变,这几个值都不会变,这一点很重要,要记住了。
在这里计算偏移量我们只需要用到ascent和descent,计算的方法跟使用getTextBounds()是一样得,不多说,直接上代码
Paint.FontMetrics fontMetrics=new Paint.FontMetrics(); mPaint.getFontMetrics(fontMetrics); float offset=(fontMetrics.descent+fontMetrics.ascent)/2; canvas.drawText(text,centerX,centerY-offset,mPaint);
效果跟getTextBounds差不多,就不上图了
getTextBounds()和FontMetircs的区别和使用场景
刚才分别介绍了这两种方式,这时候你可能会问了,什么时候用哪一种,还是无所谓,都可以。其实这两个方法还是存在一点区别的
- getTextBounds() 随着绘制内容的变化,导致中间位置也会变化,即(bounds.top+bounds.bottom)/2的值是会变得
- FontMetircs 固定的文字测量工具,中间位置不会随绘制内容发生改变
知道了其中的区别,关于二者的应用场景也就了解了
在绘制内容会产生变化的情况下,比如动态地把“bbbb”改成了“aaaa”或者其他文字,我们就用FontMetircs测量;
绘制内容不发生如何变化的,就直接用getTextBounds()就可以了
总结
以上就是关于文字绘制的全部知识,基本该注意的地方都讲到了,最近事比较多,先写这么多了哈,有什么问题随时欢迎大家评论留言。
我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Android如何回调编码后的音视频数据
有开发者提到,在RTMP推送端的基础上,希望能回调编码后的音视频数据,便于开发者对接第三方系统,如GB28181. 为此,我们加了一下接口: 1. 设置音视频callback 对应接口: /** * Set Audio Encoded Data Callback. * * @param audio_encoded_data_callback: Audio Encoded Data Callback. * * @return {0} if successful */ public native int SmartPublisherSetAudioEncodedDataCallback(long handle, Object audio_encoded_data_callback); /** * Set Video Encoded Data Callback. * * @param video_encoded_data_callback: Video Encoded Data Callback. * * @return {0} if successful */ public native ...
- 下一篇
音视频技术开发周刊 72期
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/83805954 『音视频技术开发周刊』由LiveVideoStack团队出品,专注在音视频技术领域,纵览相关技术领域的干货和新闻投稿,每周一期。点击『阅读原文』,浏览第72期内容,祝您阅读愉快。 架构 RTSP协议 SDP RTSP被用于建立的控制媒体流的传输,它为多媒体服务扮演“网络远程控制”的角色。尽管有时可以把RTSP控制信息和媒体数据流交织在一起传送,但一般情况RTSP本身并不用于转送媒体流数据。媒体数据的传送可通过RTP/RTCP等协议来完成。 Hulu直播服务难点解析(三):关键收获 Hulu在其博客发布了建立直播服务遇到的挑战及解决方案,这对于以前只提供点播服务的系统而言是一次彻底的升级。LiveVideoStack对原文进行了摘译。本文是系列文章的第三篇。 谁是最好的WebRTC SFU? 如果你计划在WebRTC中有多个参与者,那么最终可能会使用选择性转发单元(SFU)。webrtcHacks的撰稿...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS关闭SELinux安全模块
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Hadoop3单机部署,实现最简伪集群