目标:

把中文字符绘制到目标矩形的居中位置。

问题:

Android的Canvas绘图,drawText里的origin是以baseline为基准的,直接以目标矩形的bottom传进drawText,字符位置会偏下。这样写代码:

[java] view plain copy
  1. @Override
  2. publicvoidonDraw(Canvascanvas){
  3. RecttargetRect=newRect(50,50,1000,200);
  4. Paintpaint=newPaint(Paint.ANTI_ALIAS_FLAG);
  5. paint.setStrokeWidth(3);
  6. paint.setTextSize(80);
  7. StringtestString="测试:ijkJQKA:1234";
  8. paint.setColor(Color.CYAN);
  9. canvas.drawRect(targetRect,paint);
  10. paint.setColor(Color.RED);
  11. canvas.drawText(testString,targetRect.left,targetRect.bottom,paint);
  12. }
会得到难看的结果:


找方案:

首先自己动手做实验,自己定一个baseline,然后把文字画上去,再画上FontMetrics的几条线。FontMetrics里是字体图样的信息,有float型和int型的版本,都可以从Paint中获取。它的每个成员数值都是以baseline为基准计算的,所以负值表示在baseline之上。实验代码:

[java] view plain copy
  1. @Override
  2. publicvoidonDraw(Canvascanvas){
  3. Paintpaint=newPaint(Paint.ANTI_ALIAS_FLAG);
  4. paint.setStrokeWidth(3);
  5. paint.setTextSize(80);
  6. FontMetricsIntfmi=paint.getFontMetricsInt();
  7. StringtestString="测试:ijkJQKA:1234";
  8. Rectbounds1=newRect();
  9. paint.getTextBounds("测",0,1,bounds1);
  10. Rectbounds2=newRect();
  11. paint.getTextBounds("测试:ijk",0,6,bounds2);
  12. //随意设一个位置作为baseline
  13. intx=200;
  14. inty=400;
  15. //把testString画在baseline上
  16. canvas.drawText(testString,x,y,paint);
  17. //bounds1
  18. paint.setStyle(Style.STROKE);//画空心矩形
  19. canvas.save();
  20. canvas.translate(x,y);//注意这里有translate。getTextBounds得到的矩形也是以baseline为基准的
  21. paint.setColor(Color.GREEN);
  22. canvas.drawRect(bounds1,paint);
  23. canvas.restore();
  24. //bounds2
  25. canvas.save();
  26. paint.setColor(Color.MAGENTA);
  27. canvas.translate(x,y);
  28. canvas.drawRect(bounds2,paint);
  29. canvas.restore();
  30. //baseline
  31. paint.setColor(Color.RED);
  32. canvas.drawLine(x,y,1024,y,paint);
  33. //ascent
  34. paint.setColor(Color.YELLOW);
  35. canvas.drawLine(x,y+fmi.ascent,1024,y+fmi.ascent,paint);
  36. //descent
  37. paint.setColor(Color.BLUE);
  38. canvas.drawLine(x,y+fmi.descent,1024,y+fmi.descent,paint);
  39. //top
  40. paint.setColor(Color.DKGRAY);
  41. canvas.drawLine(x,y+fmi.top,1024,y+fmi.top,paint);
  42. //bottom
  43. paint.setColor(Color.GREEN);
  44. canvas.drawLine(x,y+fmi.bottom,1024,y+fmi.bottom,paint);
  45. }
获得结果:


红线是baseline,最上面的灰线是FontMetrics.top,最下面的绿线是FontMetrics.bottom。(绿色的bottom和蓝色的descent非常接近)

从图中可知,字符本身是在灰线和绿线之间居中的,知道这个就好办了。网上说的使用paint.getTextBounds的方法都不靠谱,可以看到对一个“测”字和6个字得到的bounds是不同的,图中的矩形能很好地表示这个函数得到的是字符的边界,而不是字体的边界。

FontMetrics.top的数值是个负数,其绝对值就是字体绘制边界到baseline的距离。
所以如果是把文字画在 FontMetrics高度的矩形中, drawText就应该传入 -FontMetrics.top。
要画在targetRect的居中位置,baseline的计算公式就是:

targetRect.top +(targetRect.bottom - targetRect.top) / 2 - (FontMetrics.bottom -FontMetrics.top) / 2 -FontMetrics.top

解决:

所以最开始的代码应该改成(顺便加入水平居中):

[java] view plain copy
  1. @Override
  2. publicvoidonDraw(Canvascanvas){
  3. RecttargetRect=newRect(50,50,1000,200);
  4. Paintpaint=newPaint(Paint.ANTI_ALIAS_FLAG);
  5. paint.setStrokeWidth(3);
  6. paint.setTextSize(80);
  7. StringtestString="测试:ijkJQKA:1234";
  8. paint.setColor(Color.CYAN);
  9. canvas.drawRect(targetRect,paint);
  10. paint.setColor(Color.RED);
  11. FontMetricsIntfontMetrics=paint.getFontMetricsInt();
  12. //转载请注明出处:http://blog.csdn.net/hursing
  13. intbaseline=targetRect.top+(targetRect.bottom-targetRect.top-fontMetrics.bottom+fontMetrics.top)/2-fontMetrics.top;
  14. //下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()
  15. paint.setTextAlign(Paint.Align.CENTER);
  16. canvas.drawText(testString,targetRect.centerX(),baseline,paint);
  17. }
效果(点击查看大图):



还可以去看看android sdk源码,

$android4.2/frameworks/base/corej/ava/android/text/BoringLayout.java是TextView画文字的算法

转载请注明出处:http://blog.csdn.net/hursing

更多相关文章

  1. Android---回调机制小例子
  2. Android(安卓)String.xml中的符号总结
  3. android api文档:intent阅读笔记
  4. Android用StaticLayout实现文字转化为图片效果(类似长微博发送)
  5. Android(安卓)JNI 基础知识
  6. android xml文件中进行上传图片以及获取图片
  7. 自己编译 tess-two几个库文件用于android OCR开发并合入你的工程
  8. android无法转换字符串到整型
  9. android 2d物理引擎-APEngine

随机推荐

  1. Android源码可行的下载步骤
  2. Android 网络请求框架 Retrofit2.0实践使
  3. Android中如何把bitmap存成BMP格式的图片
  4. Android培训班(32)
  5. Android-->原生API搭建Android Http服务
  6. Android中SparseArray源码实现
  7. 刘海屏适配
  8. Android彩信发送
  9. android 修改图片的颜色
  10. 设置toolbar中弹出的menu菜单在toolbar的