TextView添加标签

/ 0评 / 2

前言

在开发过程中,我们经常会遇到在下面的样式需求,如果只有一行的话,我们使用ImageView+TextView可以很快的实现,但是如果有多行文字,那就需要进行一下特殊处理了。

ImageSpan的使用

ImageSpan可以用来给TextView实现图文混排,使用方式如下

SpannableStringBuilder ssb = new SpannableStringBuilder(content);
ssb.replace(start, start + sub.length(),  Save);
ssb.setSpan(new ImageSpan(this.activity, R.mipmap.ic_mm_1), 0, 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
contentTV.setText(ssb);

效果如下

更多可以查看:https://blog.csdn.net/qq_16430735/article/details/50427978

TextView添加标签

首先我们先定义一个Tag的布局,一个非常简单的TextView

<?xml version=1.0 encoding=utf-8?>
<TextView xmlns:android=http://schemas.android.com/apk/res/android
    xmlns:tools=http://schemas.android.com/tools
    android:layout_width=wrap_content
    android:layout_height=wrap_content
    android:background=#34B5E5
    android:textColor=#FFFFFF
    tools:text=新人专享>
</TextView>

既然我们要进行图文混排,那么就需要将TextView转换为bitmap然后使用ImageSpan来替换

public class TagView extends AppCompatTextView {
    public void setTag(String tag, String text) {
        SpannableStringBuilder builder = new SpannableStringBuilder(tag);
        builder.append( );
        builder.append(text);

        TextView tagView = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.detail_pg_tag, null);
        tagView.setText(tag);
        Bitmap bitmap = convertViewToBitmap(tagView);

        Drawable d = new BitmapDrawable(getResources(), bitmap);
        d.setBounds(0, 0, tagView.getWidth(), tagView.getHeight());
        ImageSpan span = new ImageSpan(d);

        builder.setSpan(span, 0, tag.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);

        setText(builder);
    }

    private static Bitmap convertViewToBitmap(View view) {
        view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache();
        return view.getDrawingCache();
    }
}

完整代码如上,首先加载tag布局,然后转换为Bitmap。

没有其他问题了吗?

当我们的Tag的文字大小与间距和TextView的一样的时候是非常完美的,但是当我们的Tag文字大小比较大,或者比较小的时候,Tag就无法进行居中对齐了。

ImageSpan居中对齐

我们可以继承ImageSpan并重写draw方法,然后加入自己的绘制逻辑。

public class CenteredImageSpan extends ImageSpan {

    public CenteredImageSpan(Drawable d) {
        super(d);
    }

    @Override
    public void draw(@NonNull Canvas canvas, CharSequence text,
                     int start, int end, float x,
                     int top, int y, int bottom, @NonNull Paint paint) {
        // image to draw
        Drawable b = getDrawable();
        // font metrics of text to be replaced
        Paint.FontMetricsInt fm = paint.getFontMetricsInt();
        int transY = (y + fm.descent + y + fm.ascent) / 2
                - b.getBounds().bottom / 2;

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

几个参数的介绍

y:替换文字的基线坐标。

top:替换改行文字的最顶部位置。

bottom:替换改行文字的最底部位置,行间距属于上一行,因而bottom是行间距的底部位置。

参数中的y代表TextView中文字的基线位置,通过FontMetricsInt我们可以算出文字在TextView的中间位置,然后我们让图片的中间位置与TextView的中间位置对齐即可,因为图片的默认绘制是从上到下,顶部贴着TextView的顶部,所以图片的中间位置则是图片高度的一半。

具体计算逻辑

y +fontMetricsInt.descent得到字体的descent线坐标

y + fontMetricsInt.ascent得到字体的ascent线坐标

两者相加除以2,得到改行文字的中线坐标

drawable.getBounds().bottom/2得到图片中线坐标

然后两者相减,即可获得图片需要移动多长的距离可以居中

最后将相减得到的距离传给canvas.translate(x,transY)即可

参考链接:
https://www.jianshu.com/p/04fbfe2b73cf
https://juejin.im/post/5b0ed4286fb9a009f02a9a64#heading-5
https://blog.csdn.net/qq_16430735/article/details/50427978

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注