标签:
先解释一个类:Paint.FontMetrics,它表示绘制字体时的度量标准。google的官方api文档对它的字段说明如下:
@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(); }
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中的text居中对齐问题解决(无论TextView设置行距与否)
标签:
原文地址:http://www.cnblogs.com/withwind318/p/5541267.html