Make a string clickable, underlined in a TextView

16,653

Solution 1

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)

Solution 2

you can define in your strings.xml

<string name="submitText">Before you submit, please check out <a href="actual url">this link</a>

Solution 3

 <TextView  
       android:id="@+id/tvSubmit"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:layout_alignParentTop="true"  
       android:autoLink=@String/submitText //link the content of web  
       android:textColorLink="#576586" //change the color of the link  
       android:textColor="#555555" />

in activity //sample

String webLinkText = <a href="https://prativas.files.wordpress.com/2013/05/screenshot-mozilla-firefox-private-browsing.png"><img src="https://prativas.files.wordpress.com/2013/05/screenshot-mozilla-firefox-private-browsing.png" alt="Screenshot-Mozilla Firefox (Private Browsing)" width="293" height="254" class="alignnone size-full wp-image-291" /></a>  
 tvSubmit = (TextView) findViewById(R.id.tvSubmit);  
 tvSubmit.setText(Html.fromHtml(webLinkText))); 

check here for more detailed answer

Solution 4

You can try the Kotlin extension function to create text-like and also clickable with an underline.

fun TextView.colorSpannableStringWithUnderLineOne(
    prefixString: String,
    postfixString: String,
    callback: (Int) -> Unit
) {
    val spanTxt = SpannableStringBuilder()
    spanTxt.append("$prefixString ")
    spanTxt.append(" $postfixString")
    spanTxt.setSpan(object : ClickableSpan() {
        override fun onClick(widget: View) {
            callback(0)
            widget.invalidate()
        }

        override fun updateDrawState(ds: TextPaint) {
            ds.color = ContextCompat.getColor(context, R.color.highlight)
            ds.isUnderlineText = true
        }
    }, prefixString.length, spanTxt.length, 0)
    this.movementMethod = LinkMovementMethod.getInstance()
    this.setText(spanTxt, TextView.BufferType.SPANNABLE)
}

`

How to use this:

textViewLink.colorSpannableStringWithUnderLineOne(
                "Normal string",
                "Clickable string",
                callback = {
                    JLog.e("==>","Clicked")
                })
  textViewLink.invalidate()

Solution 5

In my case i needed to have a localised string with part of it to be clickable. What i did was to define a string in my resources (one for each locale) with the clickable part underlined, like this:

<string name="my_message">Blah blah blah <u>call us</u> blah blah.</string>

Then i created an extension to find the underlined text and add clickable span on it, like this:

fun CharSequence.makeUnderlineClickable(listener: (index: Int) -> Unit): SpannableString {
    val spannedString = SpannableString(this)
    spannedString.getSpans(0, length, UnderlineSpan::class.java)?.forEachIndexed { index, underlineSpan ->
        val clickableSpan = object : ClickableSpan() {
            override fun onClick(widget: View) {
                listener.invoke(index)
            }

            override fun updateDrawState(ds: TextPaint) {
                ds.isUnderlineText = true
            }
        }
        spannedString.setSpan(
            clickableSpan,
            spannedString.getSpanStart(underlineSpan),
            spannedString.getSpanEnd(underlineSpan),
            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
        )
    }
    return spannedString 
}

You can use it like this:

    textView.text = resources.getText(R.string.my_message).makeUnderlineClickable { index ->
        //handle click here
    }
    textView.movementMethod = LinkMovementMethod.getInstance()
    textView.highlightColor = Color.TRANSPARENT
Share:
16,653

Related videos on Youtube

Zbarcea Christian
Author by

Zbarcea Christian

Updated on September 26, 2022

Comments

  • Zbarcea Christian
    Zbarcea Christian over 1 year

    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.

  • 2Dee
    2Dee about 9 years
    This has no effect, because the original string doesn't actually contain a url... Read the question carefully.
  • Mobile Team ADR-Flutter
    Mobile Team ADR-Flutter about 9 years
    please check modified answer.
  • latsson
    latsson almost 3 years
    Thanks! Also to make the rest of the textView check the checkbox I added the following textView.setOnClickListener { if (selectionStart == -1 && selectionEnd == -1) { onCheckboxClick() } }