package com.zzq.mydemo;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.style.ReplacementSpan;
import androidx.annotation.IntRange;
/**
* 通用于SpannableString的icon插入类
*/
public class CommonIconSpan extends ReplacementSpan {
private Bitmap mBitmap;
private int mWidth;
private int mHeight;
private int mBgMarginTop;
private int mIntervalWidth;
private RectF mTempF = new RectF();
private Rect mTemp = new Rect();
private CommonIconSpan() {
super();
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return mWidth + mIntervalWidth;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
mTempF.set(x, top + mBgMarginTop, x + mWidth, top + mBgMarginTop + mHeight);
mTemp.set(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawBitmap(mBitmap, mTemp, mTempF, paint);
}
// ---------------------- Builder ----------------------
public static class Builder {
private CommonIconSpan instance;
private Builder(CommonIconSpan iconSpan) {
this.instance = iconSpan;
}
/**
* @param context context
* @param id 要展示的图片资源id
* @param height 要展示的图片高度,根据高度计算宽度
*/
public Builder(Context context, int id, @IntRange(from = 0) int height) {
this(new CommonIconSpan());
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), id);
this.instance.mBitmap = bitmap;
this.instance.mHeight = height;
final int resourceWidth = bitmap.getWidth();
final int resourceHeight = bitmap.getHeight();
this.instance.mWidth = height * resourceWidth / resourceHeight;
}
/**
* @param bitmap 要展示的图片资源
* @param height 要展示的图片高度,根据高度计算宽度
*/
public Builder(Bitmap bitmap, @IntRange(from = 0) int height) {
this(new CommonIconSpan());
this.instance.mBitmap = bitmap;
this.instance.mHeight = height;
final int resourceWidth = bitmap.getWidth();
final int resourceHeight = bitmap.getHeight();
this.instance.mWidth = height * resourceWidth / resourceHeight;
}
public Builder setIconBgMarginTop(@IntRange(from = 0) int bgMarginTop) {
this.instance.mBgMarginTop = bgMarginTop;
return this;
}
public Builder setIconIntervalWidth(@IntRange(from = 0) int intervalWidth) {
this.instance.mIntervalWidth = intervalWidth;
return this;
}
public CommonIconSpan build() {
return this.instance;
}
}
}
package com.zzq.mydemo;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.style.ReplacementSpan;
import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
/**
* 通用于SpannableString的带背景文字插入类
*/
public class CommonTextSpan extends ReplacementSpan {
private final int TYPE_FILL = 1;
private final int TYPE_STROKE = 2;
private final int TYPE_GRADIENT = 3;
private int mType = TYPE_FILL;
private int mHeight;
private int mTextColor = 0xffffffff;
private int mTextSize;
private int mTextPadding;
private int mBgRadius;
private int mBgColor = 0xffffffff;
private int mBgStrokeWidth;
private int mStartColor = 0xffffffff;
private int mEndColor = 0xffffffff;
private int mBgMarginTop;
private int mIntervalWidth;
private RectF mTempF = new RectF();
private CommonTextSpan() {
super();
}
private void setFill(int bgColor) {
this.mBgColor = bgColor;
this.mType = TYPE_FILL;
}
private void setBgStroke(int bgColor, int strokeWidth) {
this.mBgColor = bgColor;
this.mBgStrokeWidth = strokeWidth;
this.mType = TYPE_STROKE;
}
private void setGradient(int startColor, int endColor) {
this.mStartColor = startColor;
this.mEndColor = endColor;
this.mType = TYPE_GRADIENT;
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
float oldTextSize = paint.getTextSize();
paint.setTextSize(mTextSize);
int size = ((int) paint.measureText(text, start, end)) + mTextPadding * 2 + mIntervalWidth;
paint.setTextSize(oldTextSize);
return size;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
int color1 = paint.getColor();
switch (mType) {
case TYPE_GRADIENT:
LinearGradient linearGradient = new LinearGradient(
x, top, y, bottom,
mStartColor, mEndColor,
Shader.TileMode.CLAMP);
paint.setShader(linearGradient);
paint.setStyle(Paint.Style.FILL);
break;
case TYPE_STROKE:
paint.setColor(mBgColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(mBgStrokeWidth);
break;
default:
paint.setColor(mBgColor);
paint.setStyle(Paint.Style.FILL);
}
paint.setTextSize(mTextSize);
mTempF.set(x, top + mBgMarginTop, x + ((int) paint.measureText(text, start, end)) + mTextPadding * 2, top + mBgMarginTop + mHeight);
canvas.drawRoundRect(mTempF, mBgRadius, mBgRadius, paint);
paint.setShader(null);
paint.setColor(this.mTextColor);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeWidth(1);
float textY = top + mBgMarginTop + mHeight / 2 - (paint.descent() + paint.ascent()) / 2;
canvas.drawText(text, start, end, x + mTextPadding, textY, paint);
paint.setColor(color1);
}
// ---------------------- Builder ----------------------
public static class Builder {
private Builder(CommonTextSpan textSpan) {
this.instance = textSpan;
}
private CommonTextSpan instance;
public Builder(@IntRange(from = 0) int height) {
this(new CommonTextSpan());
this.instance.mHeight = height;
}
public Builder setTextColor(@ColorInt int textColor) {
this.instance.mTextColor = textColor;
return this;
}
public Builder setTextSize(@IntRange(from = 0) int textSize) {
this.instance.mTextSize = textSize;
return this;
}
public Builder setTextPadding(@IntRange(from = 0) int textPadding) {
this.instance.mTextPadding = textPadding;
return this;
}
public Builder setBgMarginTop(@IntRange(from = 0) int bgMarginTop) {
this.instance.mBgMarginTop = bgMarginTop;
return this;
}
public Builder setBgRadius(@IntRange(from = 0) int bgRadius) {
this.instance.mBgRadius = bgRadius;
return this;
}
public Builder setIntervalWidth(@IntRange(from = 0) int intervalWidth) {
this.instance.mIntervalWidth = intervalWidth;
return this;
}
public Builder setBgFill(@ColorInt int bgColor) {
this.instance.setFill(bgColor);
return this;
}
public Builder setBgStroke(@ColorInt int bgColor, @IntRange(from = 0) int strokeWidth) {
this.instance.setBgStroke(bgColor, strokeWidth);
return this;
}
public Builder setBgGradient(@ColorInt int startColor, @ColorInt int endColor) {
this.instance.setGradient(startColor, endColor);
return this;
}
public CommonTextSpan build() {
return this.instance;
}
}
}
参考文章:
1、https://www.jianshu.com/p/94687b604061
2、https://blog.csdn.net/liujun03/article/details/82789704
3、https://www.cnblogs.com/Alex–Yang/p/3386863.html