Html class - unsupported tags
29 Mar 2016As we know, some HTML tags are not supported by the Html
class. What can we do about it? Android SDK provides a TagHandler
interface that allows us to handle unsupported tags.
Now let’s add <strike />
tag to our lorem string from the previous post.
<string name="lorem"><![CDATA[<b>Lorem ipsum dolor</b> sit <u>amet</u>, consectetur <font color="green">adipiscing</font> elit. <i>Cras ut magna eget erat fermentum dignissim.</i> Aenean interdum ultrices sapien<sup>1</sup>. <font color="red">Vestibulum feugiat ultrices neque, vel pretium massa. Etiam tempor luctus dui eget aliquam.</font> <strike>In nec metus sit amet orci facilisis pretium.</strike>]]></string>
When we use the fromHtml
method with one parameter and run the code, we can see that it doesn’t work as intended.
Because <strike />
is not supported, we have to create TagHandler
implementation. As ImageGetter
, this interface also has only one method which notifies us when an unsupported tag is found:
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader);
It is the implementation of the TagHandler
interface with <strike />
support:
class StrikeTagHandler implements Html.TagHandler {
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if (tag.equalsIgnoreCase("strike")) {
processStrike(opening, output);
}
}
private void processStrike(boolean opening, Editable output) {
int length = output.length();
if (opening) {
startStrike(output, length);
} else {
endStrike(output, length);
}
}
private void startStrike(Editable output, int length) {
output.setSpan(new StrikethroughSpan(), length, length, Spannable.SPAN_MARK_MARK);
}
private void endStrike(Editable output, int length) {
Object obj = getLast(output, StrikethroughSpan.class);
int where = output.getSpanStart(obj);
output.removeSpan(obj);
if (where != length) {
output.setSpan(new StrikethroughSpan(), where, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
private Object getLast(Editable text, Class kind) {
Object[] objs = text.getSpans(0, text.length(), kind);
if (objs.length == 0) {
return null;
} else {
for (int i = objs.length; i > 0; i--) {
if (text.getSpanFlags(objs[i - 1]) == Spannable.SPAN_MARK_MARK) {
return objs[i - 1];
}
}
return null;
}
}
}
This code is from Android: How to use the Html.TagHandler? StackOverflow question.
When an unsupported tag is detected, the handleTag
method is triggered. We use this signal to start and finish processing this tag.
When the opening
parameter is true
, we mark a start of a struck-out text by using the setSpan
method with Spannable.SPAN_MARK_MARK
.
Next, when the end tag is detected (opening
is false
), we search for the last StrikethroughSpan
with Spannable.SPAN_MARK_MARK
flag to find start position. Then we use length
as our end position.
Finally, we apply StrikethroughSpan
by calling:
output.setSpan(new StrikethroughSpan(), where, length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
It is how we use our StrikeTagHandler
:
TextView textView = (TextView) findViewById(R.id.lorem);
String string = getString(R.string.lorem);
Spanned spanned = Html.fromHtml(string, null, new StrikeTagHandler());
textView.setText(spanned);
Below we can see the result: