效果一:
效果二:
其实我们知道如果想实现效果一很简单,两个textview横向布局一下就可以了,但是如果想要是实现效果二怎么办呢。据我所知对于前端开发来说其实效果二也很简单,前端甚至可以轻松实现富文本,但是对于安卓原生开发来说,就要使用到SpannableString
代码有注释,直接上代码
1. 任何使用
TextView txtAuthor = new TextView(mContext);txtAuthor.setText("LumoScience Publishing出版社国际版");String textToAppend = " 企业 "; // 注意:这里可以添加空格,让追加的文本和前面的文本之间有间隔TextUtils2.appendColoredText(txtAuthor, textToAppend);
2.TextUtils2 类
public class TextUtils2 {public static void appendColoredText(TextView textView, String textToAppend) {int textSizeSp = 12;int spaceW = 10;int backgroundDrawableResId = R.drawable.shape_tech_fillet_eight_f_three_whrith_bg;int textColor = Color.parseColor("#4285F5");// 1. 获取 txt_author 的文本CharSequence originalText = textView.getText();// 2. 创建一个新的 SpannableString,包含要追加的文本SpannableString spannableString = new SpannableString(textToAppend);// 3. 使用 DrawableBackgroundSpan 设置 Drawable 背景Context context = textView.getContext();Drawable backgroundDrawable = ContextCompat.getDrawable(context, backgroundDrawableResId);if (backgroundDrawable != null) {// 设置 Drawable 的边界,使其大小与文字大小相匹配int textSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSizeSp, context.getResources().getDisplayMetrics());int paddingLeft = 3; // 左边距int paddingRight = 3; // 右边距int paddingTop = 2; // 上边距int paddingBottom = 2; // 下边距ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(textColor);DrawableBackgroundSpan drawableBackgroundSpan = new DrawableBackgroundSpan(backgroundDrawable, paddingLeft, paddingRight, paddingTop, paddingBottom, foregroundColorSpan);spannableString.setSpan(drawableBackgroundSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);}// 4. 使用 ForegroundColorSpan 设置红色文字颜色//ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(textColor);//spannableString.setSpan(foregroundColorSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);// 5. 使用 AbsoluteSizeSpan 设置文字大小int textSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSizeSp, context.getResources().getDisplayMetrics());AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(textSizePx);spannableString.setSpan(absoluteSizeSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);// 6. 创建一个用于添加间距的 SpannableStringSpannableString spaceSpannableString = new SpannableString(" "); // 使用一个空格作为占位符// 7. 创建一个空的 Drawable,并设置其宽度为 10dpDrawable spaceDrawable = new Drawable() {@Overridepublic void draw(Canvas canvas) {}@Overridepublic void setAlpha(int alpha) {}@Overridepublic void setColorFilter(android.graphics.ColorFilter colorFilter) {}@Overridepublic int getOpacity() {return PixelFormat.UNKNOWN;}};int spaceWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, spaceW, context.getResources().getDisplayMetrics());spaceDrawable.setBounds(0, 0, spaceWidth, 0);// 8. 使用 DrawableMarginSpan 设置间距DrawableMarginSpan spaceMarginSpan = new DrawableMarginSpan(spaceDrawable);spaceSpannableString.setSpan(spaceMarginSpan, 0, spaceSpannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);// 9. 将间距和追加的文本添加到 SpannableStringBuilder 中SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();spannableStringBuilder.append(originalText);spannableStringBuilder.append(spaceSpannableString);spannableStringBuilder.append(spannableString);// 10. 设置 txt_author 的文本为新的 SpannableStringBuildertextView.setText(spannableStringBuilder);}
}
3. 自定义 DrawableBackgroundSpan 类
public class DrawableBackgroundSpan extends ReplacementSpan {private Drawable mDrawable;private int mPaddingLeft;private int mPaddingRight;private int mPaddingTop;private int mPaddingBottom;private ForegroundColorSpan mForegroundColorSpan;public DrawableBackgroundSpan(Drawable drawable, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom, ForegroundColorSpan foregroundColorSpan) {mDrawable = drawable;mPaddingLeft = paddingLeft;mPaddingRight = paddingRight;mPaddingTop = paddingTop;mPaddingBottom = paddingBottom;mForegroundColorSpan = foregroundColorSpan;}@Overridepublic int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {// 计算文字宽度float textWidth = paint.measureText(text, start, end);// 计算文字高度if (fm != null) {Paint.FontMetrics fontMetrics = paint.getFontMetrics();fm.ascent = (int) fontMetrics.ascent;fm.descent = (int) fontMetrics.descent;fm.top = (int) fontMetrics.top;fm.bottom = (int) fontMetrics.bottom;}// 返回总宽度,包括文字宽度和 paddingreturn (int) (textWidth + mPaddingLeft + mPaddingRight);}@Overridepublic void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {// 计算文字宽度float textWidth = paint.measureText(text, start, end);// 计算文字高度Paint.FontMetricsInt fm = paint.getFontMetricsInt();int textHeight = fm.bottom - fm.top;// 计算 Drawable 的边界int drawableLeft = (int) x;int drawableTop = top + (bottom - top - textHeight) / 2 - mPaddingTop;int drawableRight = (int) (x + textWidth + mPaddingLeft + mPaddingRight);int drawableBottom = drawableTop + textHeight + mPaddingTop + mPaddingBottom;// 设置 Drawable 的边界mDrawable.setBounds(drawableLeft, drawableTop, drawableRight, drawableBottom);// 绘制 DrawablemDrawable.draw(canvas);// 创建一个新的 TextPaint,并应用 ForegroundColorSpan 的效果TextPaint textPaint = new TextPaint(paint);if (mForegroundColorSpan != null) {mForegroundColorSpan.updateDrawState(textPaint);}// 绘制文字int centerY = (drawableTop + drawableBottom) / 2 - (fm.bottom + fm.top) / 2;canvas.drawText(text, start, end, x + mPaddingLeft, centerY, textPaint);}
}
4. shape_tech_fillet_eight_f_three_whrith_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><corners android:radius="3dp"/><solid android:color="#144285F5"/><stroke android:color="#144285F5"android:width="0.5dp"/>
</shape>