Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BackgroundColorSpan adjust height or add a padding to it

I have an app where I am displaying multiple lines, and multiple paragraphs, of formatted text in a TextView. I am using SpannableStringBuilder for this purpose.

One of the things I want to do here is to be able to highlight the text. Now I have tried using BackgroundColorSpan, but in this case, the background on the text covers the complete line-height. I want it to cover only the text instead. There seems to be no apparent way to set a vertical padding or height on this span. Just the colour.

Secondly, I also tried subclassing ReplacementSpan and implementing a backgroundSpan of my own by drawing in the draw method of this class. But this doesn't seem to support multiline highlighting.

Can anyone tell me how I can go about achieving this highlighting functionality? Basically, I want it to work like an ebook reader, preferably the Kindle or the default Book reader on Android.

like image 577
Rameez Hussain Avatar asked Sep 11 '14 09:09

Rameez Hussain


2 Answers

I tried the solution of koopuluri, but the LineBackgroundSpan is for an entire paragraph when just I wanted to highlight some words. So I found the ReplacementSpan, where we can override the function draw and draw a rectangle behind our text. You have to give it the text height.

/**
 * It's like a {@link android.text.style.BackgroundColorSpan} but we don't paint the extra line height.
 * <p/>
 */
public class BackgroundColorWithoutLineHeightSpan extends ReplacementSpan
{
    private final int mColor;
    private final int mTextHeight;

    public BackgroundColorWithoutLineHeightSpan(int color, int textHeight)
    {
        mColor = color;
        mTextHeight = textHeight;
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm)
    {
        return Math.round(measureText(paint, text, start, end));
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)
    {
        int paintColor = paint.getColor();
        RectF rect = new RectF(x, top, x + measureText(paint, text, start, end), top + mTextHeight);
        paint.setColor(mColor);
        canvas.drawRect(rect, paint);
        paint.setColor(paintColor);
        canvas.drawText(text, start, end, x, y, paint);
    }

    private float measureText(Paint paint, CharSequence text, int start, int end)
    {
        return paint.measureText(text, start, end);
    }
}
like image 55
Sylphe Avatar answered Sep 28 '22 08:09

Sylphe


You can implement LineBackgroundSpan and override:

drawBackground (Canvas c, Paint p, int left, int right, int top, int baseline, int bottom, CharSequence text, int start, int end, int lnum)

You can modify the "top" and "bottom" arguments to specify the height of the background you are drawing for a given line. The "baseline" argument is the the y-coordinate of the line that all the characters sit on (notice that the letters g, p, j etc. have some parts that fall below the baseline).

This method is applied for every line on the display for a given text. For example if the text

"this is an example , blah, blah .." 

spans 3 lines on your display, then drawBackground(...) is applied thrice, and you can use the "lnum" argument to change the behavior for certain lines if you are looking to only change the height of certain lines in the span.

like image 35
koopuluri Avatar answered Sep 28 '22 09:09

koopuluri