Android里面通常使用SpannableString或SpannableStringBuilder来拼接图片与文字,可以将其放到一个TextView控件里面来显示。如果使用过弹幕功能,通常也会使用图文混排的方式去绘制弹幕。
其中会使用ImageSpan来拼接图片,但是系统默认的ImageSpan能力非常弱,默认无法居中对齐,也无法设置图片与文字的间距,所以我们通常需要自定义ImageSpan,来解决上述问题。这里封装了一个工具类CenterSpaceImageSpan来解决这些问题。
核心逻辑在于getSize的实现,需要加上左右边距,以及绘制时Canvas translate相应的距离
/**
* 垂直居中ImageSpan,支持margin间距设置
*
*
* @author yinxuming
* @date 2020/4/2
*/
public class CenterSpaceImageSpan extends ImageSpan {
private final int mMarginLeft;
private final int mMarginRight;
public CenterSpaceImageSpan(Drawable drawable) {
this(drawable, 0, 0);
}
public CenterSpaceImageSpan(Drawable drawable,
int marginLeft, int marginRight) {
super(drawable);
mMarginLeft = marginLeft;
mMarginRight = marginRight;
}
@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();
x = mMarginLeft + x;
int transY = (y + fm.descent + y + fm.ascent) / 2 - b.getBounds().bottom / 2;
canvas.save();
canvas.translate(x, transY);
b.draw(canvas);
canvas.restore();
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable
Paint.FontMetricsInt fm) {
// Drawable d = getCachedDrawable();
// Rect rect = d.getBounds();
//
// if (fm != null) {
// fm.ascent = -rect.bottom;
// fm.descent = 0;
//
// fm.top = fm.ascent;
// fm.bottom = 0;
// }
//
// return mMarginLeft + rect.right + mMarginRight;
return mMarginLeft + super.getSize(paint, text, start, end, fm) + mMarginRight;
}
private Drawable getCachedDrawable() {
WeakReference wr = mDrawableRef;
Drawable d = null;
if (wr != null) {
d = wr.get();
}
if (d == null) {
d = getDrawable();
mDrawableRef = new WeakReference(d);
}
return d;
}
private WeakReference mDrawableRef;
}
private void customSpaceImgSpan() {
TextView mSpaceImgTv = findViewById(R.id.tv_img_space);
mSpaceImgTv.setText(buildTvImgSpace(getApplicationContext(),
"自定义图文混排效果,图片居中,图片左右间距", "100",
getResources().getDrawable(R.mipmap.ic_launcher)));
}
public static CharSequence buildTvImgSpace(Context context, String content, String praiseNumStr,
Drawable mHeadDrawable) {
BarrageDrawExtEntity mDrawExtEntity = new BarrageDrawExtEntity();
mDrawExtEntity.configDrawStyle(context, null);
SpannableStringBuilder ssb = new SpannableStringBuilder();
Drawable drawable = mHeadDrawable;
// 1. 头像
ssb.append(" ");
drawable.setBounds(0, 0, mDrawExtEntity.mImgSize, mDrawExtEntity.mImgSize);
ssb.setSpan(new CenterSpaceImageSpan(drawable, 10, 50), 0, 1, ImageSpan.ALIGN_BASELINE);
// 2. 文本
ssb.append(content + " " + praiseNumStr);
TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(null, 0,
mDrawExtEntity.mTextSize, ColorStateList.valueOf(mDrawExtEntity.mTextColor), null);
ssb.setSpan(textAppearanceSpan, 0, ssb.length() - praiseNumStr.length() - 1,
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
// 3. 点赞
drawable = context.getResources().getDrawable(R.drawable.praise_white);
drawable.setBounds(0, 0, mDrawExtEntity.mImgSize, mDrawExtEntity.mImgSize);
ssb.setSpan(new CenterSpaceImageSpan(drawable, 20, 20), ssb.length() - praiseNumStr.length() - 1,
ssb.length() - praiseNumStr.length(), ImageSpan.ALIGN_BASELINE);
// 4. 数量
textAppearanceSpan = new TextAppearanceSpan(null, 0,
mDrawExtEntity.mTextNumSize, ColorStateList.valueOf(mDrawExtEntity.mTextColor),
null);
ssb.setSpan(textAppearanceSpan,
ssb.length() - praiseNumStr.length(), ssb.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
return ssb;
}