Make a string clickable, underlined in a TextView

Zbarcea Christian picture Zbarcea Christian · Apr 2, 2015 · Viewed 15.3k times · Source

enter image description here

I want to make the string "this link" underlined and clickable, but I don't know how to achieve that.

XML file:

<string name="submitText">Before you submit, please check out &lt;u>this link&lt;/u></string>

In my fragment:

tvSubmit.setText(Html.fromHtml(getString(R.string.submitText)));

I don't want the whole string to be clickable, only the underlined section. I cannot use a horizontal LinearLayout with 2 cells, because on smaller devices the string won't have a continues look, it will be sectioned in 2 cells.

What have I tried:

tvSubmit.setMovementMethod(LinkMovementMethod.getInstance());
Spannable sp = (Spannable) tvSubmit.getText();
ClickableSpan click = new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        showLink();
    }
};
sp.setSpan(click, 0, sp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

The code above makes the whole string underlined and also the color of the text is changed into light blue.

Answer

Blackbelt picture Blackbelt · Apr 2, 2015

the problem is that you are setting the span to the whole string (sp.setSpan(click, 0, sp.length()). To fix you have to set the clickable span only on the this link. I did the same thing this way:

<string name="submitText">Before you submit, please check out %1$s</string>
<string name="this_link">this link</string>

in your Activity

String thisLink = getString(R.string.thisLink);
String yourString = getString(R.string.submitText, thisLink);
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(yourString);
spannableStringBuilder.setSpan(click,
                startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

where startIndex and endIndex are the index of thisLink in yourString. I separated the two strings because was kind of easier to look for the indexes, especially if you have to deal with translations. To calculate the startIndex you can use yourString.indexOf(thisLink), and endIndex is startIndex + the length of thisLink. I'll leave to you the ordinary checks, (negative indexes, and everything else that could cause an IndexOutBoundException)