TextView添加标签
前言
在开发过程中,我们经常会遇到在下面的样式需求,如果只有一行的话,我们使用ImageView+TextView可以很快的实现,但是如果有多行文字,那就需要进行一下特殊处理了。
ImageSpan的使用
ImageSpan可以用来给TextView实现图文混排,使用方式如下
1 2 3 4 |
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
1 2 3 4 5 6 7 8 9 |
<?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来替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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方法,然后加入自己的绘制逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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
发表评论