Android ImageSpan与TextView中的text居中对齐问题解决(无论TextView设置行距与否)
2016-07-29 16:16
766 查看
先解释一个类:Paint.FontMetrics,它表示绘制字体时的度量标准。google的官方api文档对它的字段说明如下:
ascent: 字体最上端到基线的距离,为负值。
descent:字体最下端到基线的距离,为正值。
看下图:
中间那条线就是基线,基线到上面那条线的距离就是ascent,基线到下面那条线的距离就是descent。
回到主题,我们要让imagespan与text对齐,只需把imagespan放到descent线和ascent线之间的中间位置就可以了。实现方式为重写ImageSpan类的draw方法。最终实现方法如下:
@Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { // image to draw Drawable b = getDrawable(); // font metrics of text to be replaced Paint.FontMetricsInt fm = paint.getFontMetricsInt(); int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2; canvas.save(); canvas.translate(x, transY); b.draw(canvas); canvas.restore(); }
解释下形参:
x,要绘制的image的左边框到textview左边框的距离。
y,要替换的文字的基线坐标,即基线到textview上边框的距离。
top,替换行的最顶部位置。
bottom,替换行的最底部位置。注意,textview中两行之间的行间距是属于上一行的,所以这里bottom是指行间隔的底部位置。
paint,画笔,包含了要绘制字体的度量信息。
这几个参数含义在代码中找不到说明,写了个demo测出来的。top和bottom参数只是解释下,函数里面用不上。
然后解释下代码逻辑:
getDrawable获取要绘制的image,getBounds是获取包裹image的矩形框尺寸;
y + fm.descent得到字体的descent线坐标;
y + fm.ascent得到字体的ascent线坐标;
两者相加除以2就是两条线中线的坐标;
b.getBounds().bottom是image的高度(试想把image放到原点),除以2即高度一半;
前面得到的中线坐标减image高度的一半就是image顶部要绘制的目标位置;
最后把目标坐标传递给canvas.translate函数就可以了,至于这个函数的理解先不管了。
原理上大致就这样了,最后提供本文提出问题的最终解决方案,使用自定义的ImageSpan类,只需重写它的draw函数,代码如下:
public class CenteredImageSpan extends ImageSpan {
public CenteredImageSpan(Context context, final int drawableRes) {
super(context, drawableRes);
}
@Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { // image to draw Drawable b = getDrawable(); // font metrics of text to be replaced Paint.FontMetricsInt fm = paint.getFontMetricsInt(); int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2; canvas.save(); canvas.translate(x, transY); b.draw(canvas); canvas.restore(); }
}
最后看一下效果图:
标签: android, imagespan, textview, 文字, 居中对齐, 行距
相关文章推荐
- (4.6.17.6)进程保活(Android的5.0分界线):Android5.0以上版本的force close到底发生了什么改变?
- Retrofit2的简单使用(一)
- Android 同心圆的遥控器的自定义
- Android Studio 开发中的一个小功能 使用TextView搜索ListView
- Android静态安全检测 -> 主机名弱校验
- 总结一下Android中主题(Theme)的正确玩法
- Android中计时的两种方法
- android XML实现切换效果
- Android自定义view01-ScrollView嵌套GridView
- Android WebView - 全面总结(概述、捕获url、js交互、小技巧、内存泄漏、缓存机制)
- Android 屏幕适配
- Android Studio配置Dagger2 以及butterknife
- Android反编译及重新打包
- Android Studio中有没有类似于Eclipse中的ctrl+2+L的快捷键? \Android Studio快捷键之代码提示
- 走向设计(策略模式)
- Android Studio 快捷键汇总
- 如何添加Android第三方lib
- 在Fragment中点击退出按钮,退出到登录界面后(按返回键退出程序开始的时候,退出到登录界面按返回键无法退出程序,而是返回到上一个Activity,网上说是没有finish掉上一个Activity)
- Android:TextView onClick时候,改变Text样式
- Android开发者必知的5个开源库