0

I know there are lots of answers to this question but I cant seem to get it to work... I have a ListView with some custom items consisting of TextViews and ImageViews.

I receive some data through an XML feed. One of the elements contains HTML like:

<![CDATA[ <p>My text <a href="http://myhost.com/link/to/fM" target="_blank">click here</a>.</p> ]]>

In my adapter I have this method:

private static Spanned fromHtml(String html){
    Spanned result;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
        result = Html.fromHtml(html,Html.FROM_HTML_MODE_LEGACY);
    } else {
        result = Html.fromHtml(html);
    }
    return result;
}

I'm on Android 6 so I end up in the "else" section.

I use a "holder" class to define all my TextViews and ImageViews needed for a ListView item. The holder instance is assigned like this:

view.setTag(myHolder);

and the TextView in question I populate like this:

String s = fromHtml(xmlItem.Description).toString();
myHolder.description.setText(fromHtml(s));

If I omit the

fromHtml(s)

and just setText(s) I get all the tags from my CDATA rendered

I really just want the text "click here" to be rendered as a clickable link...

What am I doing wrong?

CJe
  • 1,928
  • 3
  • 24
  • 53

1 Answers1

0

Your problem lies here:

String s = fromHtml(xmlItem.Description).toString();

The setText() method accepts anything that implements the CharSequence method. Most people usually pass String instances, which is totally fine since String implements CharSequence. But strings don't contain the information needed to handle links, so you should change that line to this instead:

Spanned s = fromHtml(xmlItem.Description);

Spanned also implements the CharSequence interface, so you can pass s to setText() just like before. And now you will see a highlighted link.

That's not the whole solution, though. You need your TextView to also know how to handle the link spans that fromHtml() creates. You use the setMovementMethod() call for this. You only need to call this once (e.g. when your convertView is null so you're creating a new view), but you should add this line as well:

myHolder.description.setMovementMethod(LinkMovementMethod.getInstance());
Ben P.
  • 52,661
  • 6
  • 95
  • 123
  • It works!!! Followed your advice and then also manually stripped the CDATA start and end tags. That did it! Thanks a million! – CJe Dec 11 '17 at 19:52
  • Just discovered that the item click event is no longer fired on my listView item :-/ Any solution to that? – CJe Dec 11 '17 at 19:59
  • @CJe so you want one thing to happen when the user clicks the link, and another thing to happen when the user clicks anywhere else? And are you using an `OnClickListener` on the view or an `OnItemClickListener` on the list? – Ben P. Dec 11 '17 at 19:59
  • Yes. Actually the link is hidden to begin with. Then when a user clicks the listView item an extra section (a description) is displayed. This description MAY contain a link. Clicking again should hide the description again. – CJe Dec 11 '17 at 20:04
  • @CJe I poked around a bit, and I'm sorry but I don't have an answer for this yet. It looks like the `MovementMethod` object is intercepting all clicks somehow... – Ben P. Dec 11 '17 at 20:15
  • Hmm... thanks for the effort tho :-) Clicking the link actually does close the listView again... maybe I can use that for something... – CJe Dec 11 '17 at 20:18
  • Got it working using https://stackoverflow.com/a/34200772/1480182. I had to use textView.setClickable(true); to prevent onItemClick() to be fired after onTouch() – CJe Dec 14 '17 at 15:10