目标:

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

问题:

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

[java] view plaincopy print?
  1. @Override
  2. public void onDraw (Canvas canvas) {
  3. Rect targetRect = new Rect(50, 50, 1000, 200);
  4. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  5. paint.setStrokeWidth(3);
  6. paint.setTextSize(80);
  7. String testString = "测试: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 plaincopy print?
  1. @Override
  2. public void onDraw (Canvas canvas) {
  3. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  4. paint.setStrokeWidth(3);
  5. paint.setTextSize(80);
  6. FontMetricsInt fmi = paint.getFontMetricsInt();
  7. String testString = "测试:ijkJQKA:1234";
  8. Rect bounds1 = new Rect();
  9. paint.getTextBounds("测", 0, 1, bounds1);
  10. Rect bounds2 = new Rect();
  11. paint.getTextBounds("测试:ijk", 0, 6, bounds2);
  12. // 随意设一个位置作为baseline
  13. int x = 200;
  14. int y = 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.centerY() - (FontMetrics.bottom - FontMetrics.top) / 2 - FontMetrics.top 优化后即:

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

解决:

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

[java] view plaincopy print?
  1. @Override
  2. public void onDraw (Canvas canvas) {
  3. Rect targetRect = new Rect(50, 50, 1000, 200);
  4. Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
  5. paint.setStrokeWidth(3);
  6. paint.setTextSize(80);
  7. String testString = "测试:ijkJQKA:1234";
  8. paint.setColor(Color.CYAN);
  9. canvas.drawRect(targetRect, paint);
  10. paint.setColor(Color.RED);
  11. FontMetricsInt fontMetrics = paint.getFontMetricsInt();
  12. // 转载请注明出处:http://blog.csdn.net/hursing
  13. int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
  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

转载于:https://www.cnblogs.com/Free-Thinker/p/5573067.html

Android Canvas drawText实现中文垂直居中相关推荐

  1. android canvas添加文字居中,android Canvas drawText 文字居中

    1首先利用canvas获取画布的宽高, //获取屏幕的宽和高 int width = canvas.getWidth(); int height = canvas.getHeight(); 2获取文字 ...

  2. Android Canvas.DrawText文本绘制

    更新时间:2022-01-23 文章目录 1. 先来一个简单的演示效果 1)MyDrawTextView.java 2)MainActivity.java 3)activity_main.xml 2. ...

  3. android drawtext 方法,关于Android Canvas.drawText方法中的坐标参数的正确解释

    canvas.drawText("www.jcodecraeer.com", x, y, paint);  x和y参数是指定字符串中心的坐标吗?还是左上角的坐标?这个问题的直观印象 ...

  4. Android: Canvas drawText()设置marginleft ,字体center_vertical的方法

    val start = context.resources.getDimensionPixelOffset(R.dimen.contact_wireless_title_margin_start)pa ...

  5. Android绘图实例(Bitmmap,Canvas,Pain的使用)动态的在图片上添加文字(canvas.drawText)

    近些天学习图像处理,今天看见了一段代码中有Bitmap时,找了些Bitmap的资料,有查看了与之有关的绘图类. BitMap代表一张位图,BitmapDrawable里封装的图片就是一个Bitmap对 ...

  6. Android动态添加5个图片资,Android绘图实例(Bitmmap,Canvas,Pain的使用)动态的在图片上添加文字(canvas.drawText)...

    近些天学习图像处理,今天看见了一段代码中有Bitmap时,找了些Bitmap的资料,有查看了与之有关的绘图类. BitMap代表一张位图,BitmapDrawable里封装的图片就是一个Bitmap对 ...

  7. android text字体居中显示,Android Canvas的drawText()和文字居中方案

    自定义View是绘制文本有三类方法 // 第一类 public void drawText (String text, float x, float y, Paint paint) public vo ...

  8. Android Canvas的drawText()和文字居中方案

    自定义View是绘制文本有三类方法: // 第一类 public void drawText (String text, float x, float y, Paint paint) public v ...

  9. Canvas DrawText详解

    声明:内容转载自HenCoder(www.hencoder.com) 感谢大神扔物线 简介 上期的 Paint 详解里已经说过,文字的绘制所能控制的内容太多太细,必须拆成单独的一期专门来讲.今天这期, ...

最新文章

  1. phpMyAdmin 数据库添加int类型的值时默认设为唯一主键的问题解决
  2. 一文总结Datawhale系列分享
  3. Freemarker模板引擎
  4. ubuntu12.04平台下a80编译环境搭建
  5. MongoDB limit 选取 skip跳过 sort排序 方法
  6. python在另一个函数中使用其他函数的变量_在另一个函数中访问函数的变量,如function() . var in python...
  7. OpenCV文档阅读笔记-cvtColor官方解析及实例
  8. javaweb(06) 初步了解HTTP协议
  9. vue使用slot分发内容与react使用prop分发内容
  10. Git-github 的基本应用
  11. Android SDK Manager设置HTTP Proxy Server代理服务器
  12. 恒指赵鑫:8.7恒指德指喊单记录与晚盘前瞻
  13. Jib快速打包Docker镜像
  14. centos7网卡开机自动down
  15. 阿里开发者工具盘点:用它!让开发事半功倍
  16. 量化交易是如何赚钱的?
  17. (四)sql多表连接查询join on的用法
  18. 数学建模(一)对变化进行建模及其解
  19. 艾伟:memcached全面剖析–2.理解memcached的内存存储
  20. linux找不到镜像文件,为什么启动u盘找不到镜像文件_u盘启动找不到映像文件的解决方法...

热门文章

  1. 软件性能测试中常见问题,性能测试常见的问题
  2. getch和getchar的区别
  3. 新手搭建网站服务器(Ubuntu+LAMP)
  4. 一个Win32程序的进化
  5. python numpy数组切片_python中numpy数组切片实验解释
  6. 弥补Reflector反编译对中文支持的不足
  7. 2019-08-21
  8. GDAL源码剖析(六)之GDAL开发及其调试
  9. 5加载stm32 keil_STM32在SRAM、FLASH中调试代码的配置方法(附详细步骤)
  10. 记一次使用 vue-admin-template 的优化历程