Actually i found big issues with all of those answers when displaying multiple lines of badges. After lots of testing and tweaking. I Finally got the best version of the above.
The basic idea is to trick the TextView by setting a much bigger text size and setting the wanted size inside the span. Also, you can see i'm drawing the badge background and text differently.
So, this is my RoundedBackgroundSpan:
public class RoundedBackgroundSpan extends ReplacementSpan {
private static final int CORNER_RADIUS = 12;
private static final float PADDING_X = GeneralUtils.convertDpToPx(12);
private static final float PADDING_Y = GeneralUtils.convertDpToPx(2);
private static final float MAGIC_NUMBER = GeneralUtils.convertDpToPx(2);
private int mBackgroundColor;
private int mTextColor;
private float mTextSize;
/**
* @param backgroundColor color value, not res id
* @param textSize in pixels
*/
public RoundedBackgroundSpan(int backgroundColor, int textColor, float textSize) {
mBackgroundColor = backgroundColor;
mTextColor = textColor;
mTextSize = textSize;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
paint = new Paint(paint); // make a copy for not editing the referenced paint
paint.setTextSize(mTextSize);
// Draw the rounded background
paint.setColor(mBackgroundColor);
float textHeightWrapping = GeneralUtils.convertDpToPx(4);
float tagBottom = top + textHeightWrapping + PADDING_Y + mTextSize + PADDING_Y + textHeightWrapping;
float tagRight = x + getTagWidth(text, start, end, paint);
RectF rect = new RectF(x, top, tagRight, tagBottom);
canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint);
// Draw the text
paint.setColor(mTextColor);
canvas.drawText(text, start, end, x + PADDING_X, tagBottom - PADDING_Y - textHeightWrapping - MAGIC_NUMBER, paint);
}
private int getTagWidth(CharSequence text, int start, int end, Paint paint) {
return Math.round(PADDING_X + paint.measureText(text.subSequence(start, end).toString()) + PADDING_X);
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
paint = new Paint(paint); // make a copy for not editing the referenced paint
paint.setTextSize(mTextSize);
return getTagWidth(text, start, end, paint);
}
}
And here is how i'm using it:
public void setTags(ArrayList<String> tags) {
if (tags == null) {
return;
}
mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26); // Tricking the text view for getting a bigger line height
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
String between = " ";
int tagStart = 0;
float textSize = 13 * getResources().getDisplayMetrics().scaledDensity; // sp to px
for (String tag : tags) {
// Append tag and space after
stringBuilder.append(tag);
stringBuilder.append(between);
// Set span for tag
RoundedBackgroundSpan tagSpan = new RoundedBackgroundSpan(bgColor, textColor, textSize);
stringBuilder.setSpan(tagSpan, tagStart, tagStart + tag.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Update to next tag start
tagStart += tag.length() + between.length();
}
mTextView.setText(stringBuilder);
}
Note:
- You can play with all sizes and constants to fit to your wanted style
- If you use an external font be sure to set android:includeFontPadding="false" otherwise it can mess up the line's height
Enjoy :)