I have an application that contains large text and sets multiple intervals for each word or sentence. I use ReplacementSpan to paint a background for each word. I cannot use BackgroundSpan because it is too simple and does not give me control over the canvas. Due to the fact that ReplacementSpan extends MetricAffectingSpan, which affects the layout of the text, completely breaking my paging. I use StaticLayout to calculate the text for each page, and StaticLayout does not allow coverage so that it can calculate a priori affecting spanning size.
Is there a replacement for ResplacementSpan? How can I draw the background that I want without affecting the size and layout of the text itself?
This is the code to replace:
public class BackgroundColorWithoutLineHeightSpan extends ReplacementSpan {
private static final float DP_ACTIVE = ViewsUtils.dpToPx(4);
private static final int DP_OUTSIDE_PADDING = (int) ViewsUtils.dpToPx(6);
private static final float DP_PHRASE = ViewsUtils.dpToPx(4);
private static final float DP_ROUNDED = ViewsUtils.dpToPx(3);
private final int mColor;
private final int mTextHeight;
private int mBorderColor;
private boolean mIsSelected;
private boolean mIsPhrase;
public BackgroundColorWithoutLineHeightSpan(int color, int textHeight, boolean isPhrase) {
mColor = color;
mTextHeight = textHeight;
mIsPhrase = isPhrase;
}
public BackgroundColorWithoutLineHeightSpan(int color, int textHeight, boolean isSelected, int borderColor, boolean isPhrase) {
mColor = color;
mTextHeight = textHeight;
mIsSelected = isSelected;
mBorderColor = borderColor;
mIsPhrase = isPhrase;
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
return Math.round(measureText(paint, text, start, end));
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
canvas.save();
Rect newRect = canvas.getClipBounds();
newRect.inset(-DP_OUTSIDE_PADDING, -DP_OUTSIDE_PADDING);
canvas.clipRect(newRect, Region.Op.REPLACE);
float measuredText = measureText(paint, text, start, end);
int paintColor = paint.getColor();
if (!mIsSelected) {
RectF rect;
rect = new RectF(x, top, x + measuredText, top + mTextHeight);
paint.setStrokeWidth(0.0f);
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rect, DP_ROUNDED, DP_ROUNDED, paint);
} else {
RectF rect;
if (mIsPhrase) {
rect = new RectF(x - DP_PHRASE, top - DP_PHRASE, x + measuredText + DP_PHRASE, top + mTextHeight + DP_PHRASE);
} else {
rect = new RectF(x - DP_ACTIVE, top - DP_ACTIVE, x + measuredText + DP_ACTIVE, top + mTextHeight + DP_ACTIVE);
}
paint.setStrokeWidth(0.0f);
paint.setColor(mColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rect, DP_ROUNDED, DP_ROUNDED, paint);
RectF border;
if (mIsPhrase) {
border = new RectF(x - DP_PHRASE, top - DP_PHRASE, x + measuredText + DP_PHRASE, top + mTextHeight + DP_PHRASE);
} else {
border = new RectF(x - DP_ACTIVE, top - DP_ACTIVE, x + measuredText + DP_ACTIVE, top + mTextHeight + DP_ACTIVE);
}
paint.setColor(mBorderColor);
paint.setStrokeWidth(4.0f);
paint.setStyle(Paint.Style.STROKE);
canvas.drawRoundRect(border, DP_ROUNDED, DP_ROUNDED, paint);
}
paint.setStyle(Paint.Style.FILL);
paint.setColor(paintColor);
canvas.drawText(text, start, end, x, y, paint);
canvas.restore();
}
private float measureText(Paint paint, CharSequence text, int start, int end) {
return paint.measureText(text, start, end);
}
}