Android TextView with Clickable Links: how to capture clicks?
Based upon another answer, here's a function setTextViewHTML() which parses the links out of a HTML string and makes them clickable, and then lets you respond to the URL.
protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
{
int start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
// Do something with span.getURL() to handle the link click...
}
};
strBuilder.setSpan(clickable, start, end, flags);
strBuilder.removeSpan(span);
}
protected void setTextViewHTML(TextView text, String html)
{
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
for(URLSpan span : urls) {
makeLinkClickable(strBuilder, span);
}
text.setText(strBuilder);
text.setMovementMethod(LinkMovementMethod.getInstance());
}
I made an easy extension function in Kotlin to catch url link clicks in a TextView by applying a new callback to URLSpan elements.
strings.xml (example link in text)
<string name="link_string">this is my link: <a href="https://www.google.com/">CLICK</a></string>
Make sure your spanned text is set to the TextView before you call "handleUrlClicks"
textView.text = getString(R.string.link_string)
This is the extension function:
/**
* Searches for all URLSpans in current text replaces them with our own ClickableSpans
* forwards clicks to provided function.
*/
fun TextView.handleUrlClicks(onClicked: ((String) -> Unit)? = null) {
//create span builder and replaces current text with it
text = SpannableStringBuilder.valueOf(text).apply {
//search for all URL spans and replace all spans with our own clickable spans
getSpans(0, length, URLSpan::class.java).forEach {
//add new clickable span at the same position
setSpan(
object : ClickableSpan() {
override fun onClick(widget: View) {
onClicked?.invoke(it.url)
}
},
getSpanStart(it),
getSpanEnd(it),
Spanned.SPAN_INCLUSIVE_EXCLUSIVE
)
//remove old URLSpan
removeSpan(it)
}
}
//make sure movement method is set
movementMethod = LinkMovementMethod.getInstance()
}
This is how I call it:
textView.handleUrlClicks { url ->
Timber.d("click on found span: $url")
}