SpannableStringBuilder实现图文混排

1.我的后面添加图片

ssb = new SpannableStringBuilder("我的后面添加图片:  ");
ssb.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 9, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

 2.我的中间添加图片

ssb = new SpannableStringBuilder("我的中 间添加图片  ");
ssb.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

 3.图片点击事件的处理

ssb = new SpannableStringBuilder("图片点击事件的处理  ");
ssb.setSpan(new ImageSpan(this, R.mipmap.ic_launcher), 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.setSpan(new ClickableSpan() {
    @Override
    public void onClick(View widget) {
      Toast.makeText(MainActivity.this, "图片点击事件的处理 ", Toast.LENGTH_SHORT).show();
    }
}, 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

 4.背景带圆角,可设置颜色,角度

 1 if (position % 2 == 0) {
 2     strShow = "300英雄" + homeDataBean.User + ":" + homeDataBean.Content;
 3     spannable = new SpannableStringBuilder(strShow);
 4     spannable.setSpan(new RadiusBackgroundSpan(Color.parseColor("#fdc14f"), 10),
 5             0, 5, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
 6 } else {
 7     strShow = "枪界" + homeDataBean.User + ":" + homeDataBean.Content;
 8     spannable = new SpannableStringBuilder(strShow);
 9     spannable.setSpan(new RadiusBackgroundSpan(Color.parseColor("#9885fc"), 10),
10             0, 2, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
11 }
 1 /**
 2  * 背景带圆角,可设置颜色,角度
 3  * Created by g on 2018/1/23.
 4  */
 5 public class RadiusBackgroundSpan extends ReplacementSpan {
 6 
 7     private int mSize;
 8     private int mColor;
 9     private int mRadius;
10 
11     /**
12      * @param color  背景颜色
13      * @param radius 圆角半径
14      */
15     public RadiusBackgroundSpan(int color, int radius) {
16         mColor = color;
17         mRadius = radius;
18     }
19 
20     @Override
21     public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
22         mSize = (int) (paint.measureText(text, start, end) + 2 * mRadius);
23         //mSize就是span的宽度,span有多宽,开发者可以在这里随便定义规则
24         //我的规则:这里text传入的是SpannableString,start,end对应setSpan方法相关参数
25         //可以根据传入起始截至位置获得截取文字的宽度,最后加上左右两个圆角的半径得到span宽度
26         return mSize;
27     }
28 
29     @Override
30     public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
31         int color = paint.getColor();//保存文字颜色
32         paint.setColor(mColor);//设置背景颜色
33         paint.setAntiAlias(true);// 设置画笔的锯齿效果
34         RectF oval = new RectF(x, y + paint.ascent(), x + mSize, y + paint.descent());
35         //设置文字背景矩形,x为span其实左上角相对整个TextView的x值,y为span左上角相对整个View的y值。paint.ascent()获得文字上边缘,paint.descent()获得文字下边缘
36         canvas.drawRoundRect(oval, mRadius, mRadius, paint);//绘制圆角矩形,第二个参数是x半径,第三个参数是y半径
37         paint.setColor(color);//恢复画笔的文字颜色
38         canvas.drawText(text, start, end, x + mRadius, y, paint);//绘制文字
39     }
40 }

6.设置图标:

if (!TextUtils.isEmpty(tagHorn)) {
 int sixe = ScreenUtils.sp2px(mContext, 15);
    EmojiconSpan imageSpan = new EmojiconSpan(mContext, R.mipmap.laba_icon,
            (int) (sixe), DynamicDrawableSpan.ALIGN_BASELINE, (int) (sixe));
    spannable.setSpan(imageSpan, strShow.indexOf(tagHorn), strShow.indexOf(tagHorn) + tagHorn.length(),
            Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
}
public class EmojiconSpan extends DynamicDrawableSpan {
    private final Context mContext;

    private final int mResourceId;

    private final int mSize;

    private final int mTextSize;

    private int mHeight;

    private int mWidth;

    private int mTop;

    private Drawable mDrawable;

    private WeakReference<Drawable> mDrawableRef;

    int nment = 5;

    public EmojiconSpan(Context context, int resourceId, int size, int alignment, int textSize) {
        super(alignment);
        mContext = context;
        mResourceId = resourceId;
        mWidth = mHeight = mSize = size;
        mTextSize = textSize;
    }

    public Drawable getDrawable() {
        if (mDrawable == null) {
            try {
                mDrawable = mContext.getResources().getDrawable(mResourceId);
                mHeight = mSize;
                mWidth = mHeight * mDrawable.getIntrinsicWidth() / mDrawable.getIntrinsicHeight();
                mTop = (mTextSize - mHeight) / 2;
                mDrawable.setBounds(0, mTop - nment, mWidth, mTop + mHeight);
            } catch (Exception e) {
                LogUtils.d(e.toString());
            }
        }
        return mDrawable;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
        //super.draw(canvas, text, start, end, x, top, y, bottom, paint);
        Drawable b = getCachedDrawable();
        canvas.save();

        int transY = bottom - b.getBounds().bottom;
        if (mVerticalAlignment == ALIGN_BASELINE) {
            transY = top + ((bottom - top) / 2) - ((b.getBounds().bottom - b.getBounds().top) / 2) - mTop;
        }

        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
    }

    private Drawable getCachedDrawable() {
        if (mDrawableRef == null || mDrawableRef.get() == null) {
            mDrawableRef = new WeakReference<Drawable>(getDrawable());
        }
        return mDrawableRef.get();
    }
}

https://blog.csdn.net/qq_33220645/article/details/53332834

原文地址:https://www.cnblogs.com/ganchuanpu/p/11688662.html