Html List tag not working in android textview. What can I do?
As you can see in the Html
class source code, Html.fromHtml(String)
does not support all HTML tags. In this very case, <ul>
and <li>
are not supported.
From the source code I have built a list of allowed HTML tags:
br
p
div
em
b
strong
cite
dfn
i
big
small
font
blockquote
tt
monospace
a
u
sup
sub
So you better use WebView
and its loadDataWithBaseURL
method. Try something like this:
String str="<html><body>A dressy take on classic gingham in a soft, textured weave of stripes that resembles twill. Take a closer look at this one.<ul><li>Trim, tailored fit for a bespoke feel</li><li>Medium spread collar, one-button mitered barrel cuffs</li><li>Applied placket with genuine mother-of-pearl buttons</li><li>;Split back yoke, rear side pleats</li><li>Made in the U.S.A. of 100% imported cotton.</li></ul></body></html>";
webView.loadDataWithBaseURL(null, str, "text/html", "utf-8", null);
How to display HTML in TextView?
You need to use Html.fromHtml()
to use HTML in your XML Strings. Simply referencing a String with HTML in your layout XML will not work.
This is what you should do in Java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>", Html.FROM_HTML_MODE_COMPACT));
} else {
textView.setText(Html.fromHtml("<h2>Title</h2><br><p>Description here</p>"));
}
And in Kotlin:
textView.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT)
} else {
Html.fromHtml(html)
}
Html a tag not working in Android textview
textview.setMovementMethod(LinkMovementMethod.getInstance());
textview.setText(Html.fromHtml(str));
Supported html tags on Android TextView
Note:
This targets API 27. Earlier versions are NOT guaranteed to support the tags seen in this list, and same for later ones (they could be removed). See the equivalent class for the applicable API versions for the applicable list.
It seems these aren't documented anywhere (correction, 2021: no longer the case), and there isn't a concrete list of when tags are added (2021: this still appears to be the case). I figured the HTML tags would need to be declared somewhere, if not in the docs, at least in the code. Fortunately, Android's HTML parsing is straight-forward enough to easily understand the relevant bits without dumpster-diving too much.
For future versions: you can either use IntelliJ or some other IDE to explore the source code of Html.java, or you can always go to the AOSP site or the equivalent GitHub repository. Using an IDE is potentially the easiest option.
Html#fromHtml(String, int)
calls Html#fromHtml(String, Int, ImageGetter, TagHandler
. The last method creates a HtmlToSpannedConverter
, and returns the result of the conversion. I dug into that code, and I found this method:
private void handleStartTag(String tag, Attributes attributes) {
if (tag.equalsIgnoreCase("br")) {
// We don't need to handle this. TagSoup will ensure that there's a </br> for each <br>
// so we can safely emit the linebreaks when we handle the close tag.
} else if (tag.equalsIgnoreCase("p")) {
startBlockElement(mSpannableStringBuilder, attributes, getMarginParagraph());
startCssStyle(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("ul")) {
startBlockElement(mSpannableStringBuilder, attributes, getMarginList());
} else if (tag.equalsIgnoreCase("li")) {
startLi(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("div")) {
startBlockElement(mSpannableStringBuilder, attributes, getMarginDiv());
} else if (tag.equalsIgnoreCase("span")) {
startCssStyle(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("strong")) {
start(mSpannableStringBuilder, new Bold());
} else if (tag.equalsIgnoreCase("b")) {
start(mSpannableStringBuilder, new Bold());
} else if (tag.equalsIgnoreCase("em")) {
start(mSpannableStringBuilder, new Italic());
} else if (tag.equalsIgnoreCase("cite")) {
start(mSpannableStringBuilder, new Italic());
} else if (tag.equalsIgnoreCase("dfn")) {
start(mSpannableStringBuilder, new Italic());
} else if (tag.equalsIgnoreCase("i")) {
start(mSpannableStringBuilder, new Italic());
} else if (tag.equalsIgnoreCase("big")) {
start(mSpannableStringBuilder, new Big());
} else if (tag.equalsIgnoreCase("small")) {
start(mSpannableStringBuilder, new Small());
} else if (tag.equalsIgnoreCase("font")) {
startFont(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("blockquote")) {
startBlockquote(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("tt")) {
start(mSpannableStringBuilder, new Monospace());
} else if (tag.equalsIgnoreCase("a")) {
startA(mSpannableStringBuilder, attributes);
} else if (tag.equalsIgnoreCase("u")) {
start(mSpannableStringBuilder, new Underline());
} else if (tag.equalsIgnoreCase("del")) {
start(mSpannableStringBuilder, new Strikethrough());
} else if (tag.equalsIgnoreCase("s")) {
start(mSpannableStringBuilder, new Strikethrough());
} else if (tag.equalsIgnoreCase("strike")) {
start(mSpannableStringBuilder, new Strikethrough());
} else if (tag.equalsIgnoreCase("sup")) {
start(mSpannableStringBuilder, new Super());
} else if (tag.equalsIgnoreCase("sub")) {
start(mSpannableStringBuilder, new Sub());
} else if (tag.length() == 2 &&
Character.toLowerCase(tag.charAt(0)) == 'h' &&
tag.charAt(1) >= '1' && tag.charAt(1) <= '6') {
startHeading(mSpannableStringBuilder, attributes, tag.charAt(1) - '1');
} else if (tag.equalsIgnoreCase("img")) {
startImg(mSpannableStringBuilder, attributes, mImageGetter);
} else if (mTagHandler != null) {
mTagHandler.handleTag(true, tag, mSpannableStringBuilder, mReader);
}
}
Which does contain all of the supported HTML tags. This list might change in future versions (it did from the original answer I had), but you can dig through the source yourself to find it in later versions. With the above code, this is the currently supported list:
br
p
ul
li
div
span
strong
b
em
cite
dfn
i
big
small
font
blockquote
tt
a
u
del
s
strike
sub
sup
img
h1
h2
h3
h4
h5
h6
Further methods cover supported attributes (in <a href="">
, href
is an attribute):
img:
src
font:
color
face
size
is apparently not supported.
a:
href
p, ul, and div calls startBlockElement, which gives one attrib:
text-align
Something special worth noting about this is the supported align variables.
- center - standard and self-explanatory
- start - aligns left
- end - aligns right
start and end might be inverted in RTL layouts - I haven't tested.
span and p, and li calls startCssStyle, which gives access to the following style
attributes:
text-decoration
background-color or background
color
text-decoration
seems to be limited to line-through
.
Why is not working the link from an html in a textview?
So there are two things.
- Your other link is just added as plain text. It does not have a
<a href
which can be detected byHtmlCompat.fromHtml
. So if you want that second text is also displayed as a link. You've to modify the response.
Example:
val sampleText =
"Esto es lo que debes hacer <a href="https://www.google.com">link aqui</a>\n" +
"\n" +
"esto es otra prueba solo con el texto <a href="https://www.google.com">https://www.google.com</a>"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val result = HtmlCompat.fromHtml(
HtmlCompat.fromHtml(
sampleText,
HtmlCompat.FROM_HTML_MODE_LEGACY
).toString(), HtmlCompat.FROM_HTML_MODE_LEGACY
)
txtDoctorComments.text = result
txtDoctorComments.movementMethod = LinkMovementMethod.getInstance()
} else {
txtDoctorComments.text =
Html.fromHtml(Html.fromHtml(sampleText).toString())
txtDoctorComments.movementMethod = LinkMovementMethod.getInstance()
}
Output:
- If you want an automatic way to detect links from plain text which does not have anchor text then you can use
Linkify.addLinks(txtDoctorComments,Linkify.WEB_URLS)
.
Example:
val sampleText =
"Esto es lo que debes hacer <a href="https://www.google.com">link aqui</a>\n" +
"\n" +
"esto es otra prueba solo con el texto https://www.google.com"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val result = HtmlCompat.fromHtml(
HtmlCompat.fromHtml(
sampleText,
HtmlCompat.FROM_HTML_MODE_LEGACY
).toString(), HtmlCompat.FROM_HTML_MODE_LEGACY
)
txtDoctorComments.text = result
Linkify.addLinks(txtDoctorComments, Linkify.WEB_URLS)
} else {
txtDoctorComments.text =
Html.fromHtml(Html.fromHtml(sampleText).toString())
txtDoctorComments.movementMethod = LinkMovementMethod.getInstance()
}
Output:
Note: You can either have an anchor tag "<a" or a plain-text link. Unfortunately, both can't be combined directly.
Related Topics
Android Mediaplayer Error (1, -2147483648)
How to Display Album Art Using Mediastore.Audio.Albums.Album_Art
Android Webview Not Loading an Https Url
Android Studio Says "Cannot Resolve Symbol" But Project Compiles
Initializing Games Client in Android
How To: Define Theme (Style) Item for Custom Widget
How to Interface with the Badgeprovider on Samsung Phones to Add a Count to the App Icon
Playing a Video in Videoview in Android
Can Multiple Android Application Access Same Firebase Database
Schedule a Work on a Specific Time with Workmanager
Edittext with Number Keypad by Default, But Allowing Alphabetic Characters
Get Android API Level of Phone Currently Running My Application
How to Programmatically Turn Off Wifi on Android Device
Dialogs/Alertdialogs: How to "Block Execution" While Dialog Is Up (.Net-Style)
Adjustpan Not Preventing Keyboard from Covering Edittext
Common Class for Asynctask in Android
How to Create Empty Constructor for Data Class in Kotlin Android