简介
开发中需要为TextView头尾添加标签图片,并且尾部标签不被挤出,考虑了几种可能的方案:
- 动态计算TextView的文本长度和每行的宽度
- 使用TextView的Span
- 自定义一个View,自己绘制文本和标签图片
对比
- 第一种由于Android的碎片化极其严重,各种机型,各种字体等等,更重要的是TextView并没有对应的API可以进行回去绘制。PASS。
- 第二种可行性还是不错的,Android原生支持了很多类型的Span。但是有一个问题就是没有可以当图片和文本居中的Span可以使用。如果使用就必须自定义一个Span。查看DynamicDrawableSpan,ImageSpan等Span的源码,发现自定义的话是可以满足的。待定。
- 第三种自己可以定制自己想实现的各种效果。但是适配性比较难保证。待定
最后综合考虑,实验第二种是否能满足,如果不能满足,则使用第三种。
方案二
自定义Span
涉及到的类:Paint.FontMetrics
,它表示绘制字体时的度量标准。Google的官方api文档对它的字段说明如下:
- ascent: 字体最上端到基线的距离,为负值。
- descent:字体最下端到基线的距离,为正值。
- bottom: 最下字符到baseline的距离。即为descent的最大值
- top: 最高字符到baseline的距离。即为ascent的最大值
- leading: 上一行字符的descent到下一行字符ascent的距离
回到主题,我们要让图片与Textview
对齐,只需把图片放到descent线和ascent线之间的中间位置就可以了。实现方式为仿照DynamicDrawableSpan,重写DynamicDrawableSpan类的draw方法。最终实现如下:
/** |
文本长度问题
既然图片插入和居中没有问题,那么最后一个问题就是如何保证尾部标签不被挤出呢。搜索到[Android]TextUtils.ellipsize()截取指定长度字符串(附图文混排),让我注意到TextUtils.html.ellipsize(text, p, avail, where)这个方法。其中avail
字段代表的是有效长度,text
代码需要截取的字段。这个方法是TextView截取的静态方法。经测试,可用。
avail
字段必须是精确长度,意思就是说,他会按照你传入的长度对text
截取。一开始,我是计算长度是按照:
View的长度 * MaxLines - 图片已占用的长度 - padding(l,t,r,b)
当把截取后的文本设为TextView
时,TextView
会根据自身的属性进行布局,当文本文本换行时,如果遇到当前行空出部分字符的情况,就会导致实际的精确长度比我计算时的要短,最后的标签图片还是会截。无奈,经调试确认方案是:在计算时,每行减去textsize / 3
,即:
View的长度 * maxLines - 图片已占用的长度 - padding(l,t,r,b) - textsize / 3 * (maxLines - 1)
最后计算的代码如下:
/** |
效果
方案三
TODO