效果一:
效果二:
其实我们知道如果想实现效果一很简单,两个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. 创建一个用于添加间距的 SpannableString
SpannableString spaceSpannableString = new SpannableString(" "); // 使用一个空格作为占位符
// 7. 创建一个空的 Drawable,并设置其宽度为 10dp
Drawable spaceDrawable = new Drawable() {
@Override
public void draw(Canvas canvas) {
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(android.graphics.ColorFilter colorFilter) {
}
@Override
public 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 的文本为新的 SpannableStringBuilder
textView.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;
}
@Override
public 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;
}
// 返回总宽度,包括文字宽度和 padding
return (int) (textWidth + mPaddingLeft + mPaddingRight);
}
@Override
public 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);
// 绘制 Drawable
mDrawable.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>