How about the next code (based on this link) :
public class TextViewHtmlTagHandler implements TagHandler
{
/**
* Keeps track of lists (ol, ul). On bottom of Stack is the outermost list
* and on top of Stack is the most nested list
*/
Stack<String> lists =new Stack<String>();
/**
* Tracks indexes of ordered lists so that after a nested list ends
* we can continue with correct index of outer list
*/
Stack<Integer> olNextIndex =new Stack<Integer>();
/**
* List indentation in pixels. Nested lists use multiple of this.
*/
private static final int indent =10;
private static final int listItemIndent =indent*2;
private static final BulletSpan bullet =new BulletSpan(indent);
@Override
public void handleTag(final boolean opening,final String tag,final Editable output,final XMLReader xmlReader)
{
if(tag.equalsIgnoreCase("ul"))
{
if(opening)
lists.push(tag);
else lists.pop();
}
else if(tag.equalsIgnoreCase("ol"))
{
if(opening)
{
lists.push(tag);
olNextIndex.push(Integer.valueOf(1)).toString();// TODO: add support for lists starting other index than 1
}
else
{
lists.pop();
olNextIndex.pop().toString();
}
}
else if(tag.equalsIgnoreCase("li"))
{
if(opening)
{
if(output.length()>0&&output.charAt(output.length()-1)!='\n')
output.append("\n");
final String parentList=lists.peek();
if(parentList.equalsIgnoreCase("ol"))
{
start(output,new Ol());
output.append(olNextIndex.peek().toString()+". ");
olNextIndex.push(Integer.valueOf(olNextIndex.pop().intValue()+1));
}
else if(parentList.equalsIgnoreCase("ul"))
start(output,new Ul());
}
else if(lists.peek().equalsIgnoreCase("ul"))
{
if(output.charAt(output.length()-1)!='\n')
output.append("\n");
// Nested BulletSpans increases distance between bullet and text, so we must prevent it.
int bulletMargin=indent;
if(lists.size()>1)
{
bulletMargin=indent-bullet.getLeadingMargin(true);
if(lists.size()>2)
// This get's more complicated when we add a LeadingMarginSpan into the same line:
// we have also counter it's effect to BulletSpan
bulletMargin-=(lists.size()-2)*listItemIndent;
}
final BulletSpan newBullet=new BulletSpan(bulletMargin);
end(output,Ul.class,new LeadingMarginSpan.Standard(listItemIndent*(lists.size()-1)),newBullet);
}
else if(lists.peek().equalsIgnoreCase("ol"))
{
if(output.charAt(output.length()-1)!='\n')
output.append("\n");
int numberMargin=listItemIndent*(lists.size()-1);
if(lists.size()>2)
// Same as in ordered lists: counter the effect of nested Spans
numberMargin-=(lists.size()-2)*listItemIndent;
end(output,Ol.class,new LeadingMarginSpan.Standard(numberMargin));
}
}
else if(opening)
Log.d("TagHandler","Found an unsupported tag "+tag);
}
private static void start(final Editable text,final Object mark)
{
final int len=text.length();
text.setSpan(mark,len,len,Spanned.SPAN_MARK_MARK);
}
private static void end(final Editable text,final Class<?> kind,final Object... replaces)
{
final int len=text.length();
final Object obj=getLast(text,kind);
final int where=text.getSpanStart(obj);
text.removeSpan(obj);
if(where!=len)
for(final Object replace : replaces)
text.setSpan(replace,where,len,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return;
}
private static Object getLast(final Spanned text,final Class<?> kind)
{
/*
* This knows that the last returned object from getSpans()
* will be the most recently added.
*/
final Object[] objs=text.getSpans(0,text.length(),kind);
if(objs.length==0)
return null;
return objs[objs.length-1];
}
private static class Ul
{
}
private static class Ol
{
}
}