Android图文混排ImageSpan居中,以及设置间距问题

本文介绍了Android中如何通过自定义ImageSpan解决系统默认图文混排无法居中和设置间距的问题。通过封装CenterSpaceImageSpan工具类,详细讲解了自定义效果对比、自定义ImageSpan的核心逻辑,以及调用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android里面通常使用SpannableString或SpannableStringBuilder来拼接图片与文字,可以将其放到一个TextView控件里面来显示。如果使用过弹幕功能,通常也会使用图文混排的方式去绘制弹幕。

其中会使用ImageSpan来拼接图片,但是系统默认的ImageSpan能力非常弱,默认无法居中对齐,也无法设置图片与文字的间距,所以我们通常需要自定义ImageSpan,来解决上述问题。这里封装了一个工具类CenterSpaceImageSpan来解决这些问题。

一、自定义效果对比

二、自定义ImageSpan

核心逻辑在于getSize的实现,需要加上左右边距,以及绘制时Canvas translate相应的距离


/**
 * 垂直居中ImageSpan,支持margin间距设置
 * <p>
 *
 * @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<Drawable> wr = mDrawableRef;
        Drawable d = null;

        if (wr != null) {
            d = wr.get();
        }

        if (d == null) {
            d = getDrawable();
            mDrawableRef = new WeakReference<Drawable>(d);
        }

        return d;
    }

    private WeakReference<Drawable> mDrawableRef;
}

 

三、调用Demo


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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值