5

Currently I have a SpannableString object with multiple Clickable objects set to it. So one string has many Clickable objects and depending on which word/section the User clicks the app will go on and do the processing of that click event. The other day I had asked here on stackoverflow about getting rid of the blue underline on part of the word in the SpannableString and the answer was to sub class the ClickableSpan class, and override the updateDrawState method and setting the underlineText to false which worked.

My Problem: Is it possible to put a border around the Clickable object in the SpannableString? So basically each Clickable object/string has to have there own border.

I thought maybe the updateDrawState method maybe able to help but it didn't. Does anybody know how this can be achieved?

Thanks.

Ash
  • 1,241
  • 1
  • 9
  • 16
  • Take a look at how `BackgroundColorSpan` does what it does -- a border is effectively just a hollow background. – CommonsWare Apr 16 '13 at 00:04
  • @CommonsWare I just tried BackgroundColorSpan but it is setting the background to red, not creating a red border as I am after? – Ash Apr 16 '13 at 00:26
  • @CommonsWare Is there a special way of using/tweaking BackgroundColorSpan so it can display a red border/outline? – Ash Apr 16 '13 at 01:56
  • My point was for you to look at the *implementation* of `BackgroundColorSpan`, to learn how *you* can write *your own* `OutlinedClickableSpan` or some such. – CommonsWare Apr 16 '13 at 12:57

1 Answers1

5

I extended ReplacementSpan to make an outlined span. Unfortunately, I can't manage to make them wrap, but if you're only looking to apply your outline to a couple words, it should work fine. To make this clickable, you'd just use the subclass you mentioned setSpan(ClickableSpanWithoutUnderline...) before you set this one.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_replacement_span);

    final Context context = this;
    final TextView tv = (TextView) findViewById(R.id.tv);


    Spannable span = Spannable.Factory.getInstance().newSpannable("Some string");
    span.setSpan(new BorderedSpan(context), 0, span.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 

    tv.setText(span, TextView.BufferType.SPANNABLE);
}


public static class BorderedSpan extends ReplacementSpan {
    final Paint mPaintBorder, mPaintBackground;
    int mWidth;
    Resources r;
    int mTextColor;

    public BorderedSpan(Context context) {
        mPaintBorder = new Paint();
        mPaintBorder.setStyle(Paint.Style.STROKE);
        mPaintBorder.setAntiAlias(true);

        mPaintBackground = new Paint();
        mPaintBackground.setStyle(Paint.Style.FILL);
        mPaintBackground.setAntiAlias(true);

        r = context.getResources();

        mPaintBorder.setColor(Color.RED);
        mPaintBackground.setColor(Color.GREEN);
        mTextColor = Color.BLACK;
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        //return text with relative to the Paint
        mWidth = (int) paint.measureText(text, start, end);
        return mWidth;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
        canvas.drawRect(x, top, x + mWidth, bottom, mPaintBackground);
        canvas.drawRect(x, top, x + mWidth, bottom, mPaintBorder);
        paint.setColor(mTextColor); //use the default text paint to preserve font size/style
        canvas.drawText(text, start, end, x, y, paint);
    }
}
Community
  • 1
  • 1
adamdport
  • 11,687
  • 14
  • 69
  • 91