Android Canvas drawText实现中文垂直居中
目标:
把中文字符绘制到目标矩形的居中位置。
问题:
Android的Canvas绘图,drawText里的origin是以baseline为基准的,直接以目标矩形的bottom传进drawText,字符位置会偏下。这样写代码:
- @Override
- public void onDraw (Canvas canvas) {
- Rect targetRect = new Rect(50, 50, 1000, 200);
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setStrokeWidth(3);
- paint.setTextSize(80);
- String testString = "测试:ijkJQKA:1234";
- paint.setColor(Color.CYAN);
- canvas.drawRect(targetRect, paint);
- paint.setColor(Color.RED);
- canvas.drawText(testString, targetRect.left, targetRect.bottom, paint);
- }
会得到难看的结果:
找方案:
首先自己动手做实验,自己定一个baseline,然后把文字画上去,再画上FontMetrics的几条线。FontMetrics里是字体图样的信息,有float型和int型的版本,都可以从Paint中获取。它的每个成员数值都是以baseline为基准计算的,所以负值表示在baseline之上。实验代码:
- @Override
- public void onDraw (Canvas canvas) {
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setStrokeWidth(3);
- paint.setTextSize(80);
- FontMetricsInt fmi = paint.getFontMetricsInt();
- String testString = "测试:ijkJQKA:1234";
- Rect bounds1 = new Rect();
- paint.getTextBounds("测", 0, 1, bounds1);
- Rect bounds2 = new Rect();
- paint.getTextBounds("测试:ijk", 0, 6, bounds2);
- // 随意设一个位置作为baseline
- int x = 200;
- int y = 400;
- // 把testString画在baseline上
- canvas.drawText(testString, x, y, paint);
- // bounds1
- paint.setStyle(Style.STROKE); // 画空心矩形
- canvas.save();
- canvas.translate(x, y); // 注意这里有translate。getTextBounds得到的矩形也是以baseline为基准的
- paint.setColor(Color.GREEN);
- canvas.drawRect(bounds1, paint);
- canvas.restore();
- // bounds2
- canvas.save();
- paint.setColor(Color.MAGENTA);
- canvas.translate(x, y);
- canvas.drawRect(bounds2, paint);
- canvas.restore();
- // baseline
- paint.setColor(Color.RED);
- canvas.drawLine(x, y, 1024, y, paint);
- // ascent
- paint.setColor(Color.YELLOW);
- canvas.drawLine(x, y+fmi.ascent, 1024, y+fmi.ascent, paint);
- // descent
- paint.setColor(Color.BLUE);
- canvas.drawLine(x, y+fmi.descent, 1024, y+fmi.descent, paint);
- // top
- paint.setColor(Color.DKGRAY);
- canvas.drawLine(x, y+fmi.top, 1024, y+fmi.top, paint);
- // bottom
- paint.setColor(Color.GREEN);
- canvas.drawLine(x, y+fmi.bottom, 1024, y+fmi.bottom, paint);
- }
获得结果:
红线是baseline,最上面的灰线是FontMetrics.top,最下面的绿线是FontMetrics.bottom。(绿色的bottom和蓝色的descent非常接近)
从图中可知,字符本身是在灰线和绿线之间居中的,知道这个就好办了。网上说的使用paint.getTextBounds的方法都不靠谱,可以看到对一个“测”字和6个字得到的bounds是不同的,图中的矩形能很好地表示这个函数得到的是字符的边界,而不是字体的边界。
FontMetrics.top的数值是个负数,其绝对值就是字体绘制边界到baseline的距离。 所以如果是把文字画在 FontMetrics高度的矩形中, drawText就应该传入 -FontMetrics.top。 要画在targetRect的居中位置,baseline的计算公式就是: targetRect.centerY() - (FontMetrics.bottom - FontMetrics.top) / 2 - FontMetrics.top 优化后即:
(targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2
解决:
所以最开始的代码应该改成(顺便加入水平居中):
- @Override
- public void onDraw (Canvas canvas) {
- Rect targetRect = new Rect(50, 50, 1000, 200);
- Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
- paint.setStrokeWidth(3);
- paint.setTextSize(80);
- String testString = "测试:ijkJQKA:1234";
- paint.setColor(Color.CYAN);
- canvas.drawRect(targetRect, paint);
- paint.setColor(Color.RED);
- FontMetricsInt fontMetrics = paint.getFontMetricsInt();
- // 转载请注明出处:http://blog.csdn.net/hursing
- int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
- // 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
- paint.setTextAlign(Paint.Align.CENTER);
- canvas.drawText(testString, targetRect.centerX(), baseline, paint);
- }
效果(点击查看大图):
还可以去看看android sdk源码,
转载请注明出处:http://blog.csdn.net/hursing
Android Canvas drawText实现中文垂直居中的更多相关文章
- 关于Android Canvas.drawText方法中的坐标参数的正确解释
canvas.drawText("www.jcodecraeer.com", x, y, paint); x和y参数是指定字符串中心的坐标吗?还是左上角的坐标?这个问题的直观印象 ...
- Android Canvas.drawText方法中的坐标参数的正确解释
摘要 canvas.drawText(www.jcodecraeer.com, x, y, paint); x和y参数是指定字符串中心的坐标吗?还是左上角的坐标?这个问题的直观印象应该是左上角的坐标, ...
- android Canvas drawText 文字居中
1首先利用canvas获取画布的宽高, //获取屏幕的宽和高int width = canvas.getWidth();int height = canvas.getHeight(); 2获取文字的宽 ...
- android canvas drawtext 字高
Paint pFont = new Paint(); Rect rect = new Rect(); pFont.getTextBounds("豆", 0, 1, rect); L ...
- android中画文字的换行 办法(对于遇到canvas.drawText(String s )无法实现换行问题的解决)
在使用canvas.drawText()绘制文字的时候,发现,如果需要绘制的文字较长,需要换行,通过在文字中加上“\n"或者”\r\n"都无法实现换行,如果非要使用canvas.d ...
- android Canvas 和 Paint用法
自定义view里面的onDraw方法,在这里我们可以绘制各种图形,onDraw里面有两个API我们需要了解清楚他们的用法:Canvas 和 Paint. Canvas翻译成中文就是画布的意思,Canv ...
- 如何“任性”使用Android的drawText()
Android的canvas上可以画很多基本形状,诸如:圆,矩形,线条等等,其中当属文字即drawText()较难理解和使用(额,这只是就个人感受),下面将慢慢介绍下如何简单使用drawText(). ...
- Android Canvas绘图详解(图文)
编辑推荐:稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! Andr ...
- 【转】Android Canvas绘图详解(图文)
转自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1212/703.html Android Canvas绘图详解(图文) 泡 ...
随机推荐
- ThinkPHP HTML标签代码和UBB互相转换
1.UBB 转为 HTML TP的扩展里面自带一个ubb方法,用这个方法就能把用户输入的ubb格式代码转换为HTML标签的代码.这里用到的基本知识就是正则表达式啦,今天先不讲正则表达式. 来看一下TP ...
- 基于Lua的清除类游戏算法
最近在开发游戏,用Lua语言.习惯了其它的语言,然后对Lua的一些语法很不习惯. 比如table的元素个数的取值,比switch语句等等. 不过没有办法,还是要运用Lua来写游戏的.看来学C++还真的 ...
- init_sequence所对应的函数
一.init_sequence内容 init_fnc_t *init_sequence[] = { cpu_init, /* basic cpu dependent setup */ board_in ...
- 如何通过友盟分析发布后App崩溃日志-b
要分析崩溃日志,首先需要保留发布时的编译出来的.xcarchive文件.这个文件包含了.DSYM文件. 我一般的做法是,发布成功后,把这个文件.xcarchive直接提交到代码版本库对应的版本分支里, ...
- uitableview的空白处不能响应 touchesbegan 事件
现在的uitableview 的上面 响应不了 touchesbegan 事件 可能算是苹果的一个bug吧,不知道以后会不会改变 今天试了好久 都不行 最后 写了个字类 继承自 ...
- Warm up 2
hdu4619:http://acm.hdu.edu.cn/showproblem.php?pid=4619 题意:题目大意:给你两种纸牌 ,一种水平放置共有n张 ,一种竖直放置共有m张.水平放置的纸 ...
- 谈谈在keil下的代码定位
关于C语言,我们一般都知道对于RAM定位可以用关键字 _at_,但对于程序代码定位往往感到很迷惑, 其实keil中的程序代码定位功能极为强大 Menu: Options for Target 'Tar ...
- ? super T ? extends T
? super T ?保存的是 T类型或者T类型的父类 ? extends T ?保存的是 T类型或者T类型的子类
- luoguP2267 琪琪的项链
题目:http://www.luogu.org/problem/show?pid=2267 题解:这题略吊. 看了之后发现不能用组合数学直接得出公式,然后如果直接暴力也不知道如何去排除两个颜色序列相同 ...
- org.springframework.web.servlet.view
view包下面的类和接口 description:提供view和viewResolver的标准实现,也提供一些抽象基类.Spring MVC已经提供了 JSPs, Velocity, XSLT等视图的 ...