Android---ImageSpan + SpannableStringBuilder 图文混排解决表情文字高度不一致排版错乱问题(设置padding 行间距依然生效)

前言

  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);

效果:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值