Android TextView图文混排,图片和文字居中对齐

来源:互联网 发布:时标网络图 软件 编辑:程序博客网 时间:2024/06/05 20:56

TextView用来显示文本是最普通的用法了,有些情况需要我们再文本中显示图片,比如显示表情,下边来说说处理方法.

1.下图是项目中一个UI需求
这里写图片描述

如图需要在文本的前边显示新上标签,开始的处理方法是用了两个空间分别显示标签和文本,但是有个问题是第二行的文本不能顶头对齐,很不美观.

我们可以通过图文混排来解决上述问题,通过SpannableString来实现,在相应位置使用ImageSpan替换即可,但是imageSpan只提供了两种对齐方式,如下所示:
/**
底部对齐
*/
public static final int ALIGN_BOTTOM = 0;

/**
基线对齐
*/
public static final int ALIGN_BASELINE = 1;

但是通常UI设计肯定是图片和文字居中对齐
这里需要扩展继承ImageSpan,重写它的onDraw()方法

public class CenterAlignImageSpan extends ImageSpan {    public CenterAlignImageSpan(Drawable drawable) {        super(drawable);    }    public CenterAlignImageSpan(Bitmap b) {        super(b);    }    @Override    public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,            @NonNull Paint paint) {        Drawable b = getDrawable();        Paint.FontMetricsInt fm = paint.getFontMetricsInt();        int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;//计算y方向的位移        canvas.save();        canvas.translate(x, transY);//绘制图片位移一段距离        b.draw(canvas);        canvas.restore();    }}

这是自定义ImageSpan的代码,非常少。主要的原理是把图片绘制在字体的descent线和ascent的中点位置。
在Activity中使用方法如下

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        TextView tv = (TextView) findViewById(R.id.test);        SpannableString sp = new SpannableString("图文混排测排测试图文混排测试图文混排测试图文混排测试图");        //获取一张图片        Drawable drawable = getDrawable(R.drawable.star);        drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());        //居中对齐imageSpan        CenterAlignImageSpan imageSpan = new CenterAlignImageSpan(drawable);        sp.setSpan(imageSpan, 0, 1, ImageSpan.ALIGN_BASELINE);        //普通imageSpan 做对比        ImageSpan imageSpan2 = new ImageSpan(drawable);        sp.setSpan(imageSpan2, 3, 4, ImageSpan.ALIGN_BASELINE);        tv.setText(sp);    }}