前言
android图文混排的最常见实现方案就是使用SpannableStringBuilder ,比如我们要实现聊天框输入表情的功能就需要用到其实现。但是当我们的icon图标大于或者小于字体高度时会导致字体跟图标不能垂直居中对齐,这样UI显示就不是很友好。ImageSpan自带的DynamicDr awableSpan.ALIGN_CENTER配置会在换行,或者设置了padding等情况下失效造成错乱。网上检索出的方案在我实践验证下大部分都存在很大瑕疵,索性功夫不负有心人找到了下面这个相对可靠的解决方案可以直接拿来复用。
一、继承ImageSpan重写绘制方法
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.style.ImageSpan;
import java.lang.ref.WeakReference;
public class VerticalImageSpan2 extends ImageSpan {
private WeakReference<Drawable> mDrawableRef;
public VerticalImageSpan2(Context context, Bitmap bitmap, int verticalAlignment) {
super(context, bitmap, verticalAlignment);
}
public VerticalImageSpan2(Context context, int resId, int verticalAlignment) {
super(context, resId, verticalAlignment);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end,
Paint.FontMetricsInt fontMetricsInt) {
Drawable drawable = getDrawable();
Rect rect = drawable.getBounds();
if (fontMetricsInt != null) {
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int drHeight = rect.bottom - rect.top;
int centerY = fmPaint.ascent + fontHeight / 2;
fontMetricsInt.ascent = centerY - drHeight / 2;
fontMetricsInt.top = fontMetricsInt.ascent;
fontMetricsInt.bottom = centerY + drHeight / 2;
fontMetricsInt.descent = fontMetricsInt.bottom;
}
return rect.right;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
int bottom, Paint paint) {
Drawable drawable = getCachedDrawable();
canvas.save();
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
int fontHeight = fmPaint.descent - fmPaint.ascent;
int centerY = y + fmPaint.descent - fontHeight / 2;
int transY = centerY - (drawable.getBounds().bottom - drawable.getBounds().top) / 2;
canvas.translate(x, transY);
drawable.draw(canvas);
canvas.restore();
}
private Drawable getCachedDrawable() {
WeakReference<Drawable> wr = mDrawableRef;
Drawable d = null;
if (wr != null) {
d = wr.get();
}
if (d == null) {
d = getDrawable();
mDrawableRef = new WeakReference<>(d);
}
return d;
}
}
二、实践
VerticalImageSpan2 imageSpan = new VerticalImageSpan2(context, iconData.getResId(),DynamicDrawableSpan.ALIGN_CENTER);
SpannableStringBuilder spannableStringBuilder = SpannableStringBuilder.valueOf("[" + iconData.getCode()+ "]");
spannableStringBuilder.setSpan(imageSpan,0, iconData.getCode().length() + 2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
editText.append(spannableStringBuilder);
效果: