para - manual de programacion android pdf
La etiqueta Html List no funciona en la vista de texto de Android. ¿que puedo hacer? (14)
La etiqueta Html List no funciona en Android TextView. Este es mi contenido de cuerda:
String str="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>";
Lo cargué en una vista de texto como esta:
textview.setText(Html.fromHtml(str));
El resultado parece un párrafo. ¿Que puedo hacer? ¿Hay alguna solución para eso?
Editar:
webview.loadData(str,"text/html","utf-8");
¿Qué tal el próximo código (basado en este enlace ):
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
{
}
}
Claro, hay una forma de mostrar viñetas en Android TextView. Puede reemplazar las etiquetas <li>
con •
(que es código HTML para viñeta).
Si desea probar otros íconos de lista, use el preferido de la tabla es este enlace;
Como puede ver en el código fuente de la clase Html
, Html.fromHtml(String)
no admite todas las etiquetas HTML. En este caso, <ul>
y <li>
no son compatibles.
Del código fuente he creado una lista de etiquetas HTML permitidas:
-
br
-
p
-
div
-
em
-
b
-
strong
-
cite
-
dfn
-
i
-
big
-
small
-
font
-
blockquote
-
tt
-
monospace
-
a
-
u
-
sup
-
sub
Entonces es mejor usar WebView
y su método loadDataWithBaseURL
. Pruebe algo como esto:
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);
Diferente solución usando LeadingMarginSpan. Maneja listas ordenadas y desordenadas, así como la anidación.
public class ListTagHandler implements TagHandler
{
private int m_index = 0;
private List< String > m_parents = new ArrayList< String >( );
@Override
public void handleTag( final boolean opening, final String tag, Editable output, final XMLReader xmlReader )
{
if( tag.equals( "ul" ) || tag.equals( "ol" ) || tag.equals( "dd" ) )
{
if( opening )
{
m_parents.add( tag );
}
else m_parents.remove( tag );
m_index = 0;
}
else if( tag.equals( "li" ) && !opening ) handleListTag( output );
}
private void handleListTag( Editable output )
{
if( m_parents.get(m_parents.size()-1 ).equals( "ul" ) )
{
output.append( "/n" );
String[ ] split = output.toString( ).split( "/n" );
int lastIndex = split.length - 1;
int start = output.length( ) - split[ lastIndex ].length( ) - 1;
output.setSpan( new BulletSpan( 15 * m_parents.size( ) ), start, output.length( ), 0 );
}
else if( m_parents.get(m_parents.size()-1).equals( "ol" ) )
{
m_index++ ;
output.append( "/n" );
String[ ] split = output.toString( ).split( "/n" );
int lastIndex = split.length - 1;
int start = output.length( ) - split[ lastIndex ].length( ) - 1;
output.insert( start, m_index + ". " );
output.setSpan( new LeadingMarginSpan.Standard( 15 * m_parents.size( ) ), start, output.length( ), 0 );
}
}
}
El proyecto de muestra completo se encuentra en https://bitbucket.org/Kuitsi/android-textview-html-list .
La imagen de muestra está disponible en https://kuitsi.bitbucket.io/3150400_screen.png
Esta solución está más cerca de la respuesta de Masha . Algunos códigos también se toman de la clase interna android.text.Html.HtmlToSpannedConverter
. Admite listas anidadas ordenadas y desordenadas, pero los textos demasiado largos en listas ordenadas siguen alineados con el número de artículo en lugar de con el texto. Las listas mixtas (ol y ul) también necesitan algo de trabajo. El proyecto de ejemplo contiene la implementación de Html.TagHandler que se pasa a Html.fromHtml (String, ImageGetter, TagHandler) .
Editar: para una compatibilidad más amplia con etiquetas HTML, también puede valer la pena intentar https://github.com/NightWhistler/HtmlSpanner .
Parece una vieja pregunta, tengo el mismo problema, lo que hice fue anular el TagHandler predeterminado, soy nuevo en y Android, y valoro cualquier corrección o mejor método :) Este me funcionó.
package com.tumblr.amangautam.cars;
import org.xml.sax.XMLReader;
import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.Html.TagHandler;
import android.util.Log;
public class MyTagHandler implements TagHandler{
boolean first= true;
String parent=null;
int index=1;
@Override
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if(tag.equals("ul")) parent="ul";
else if(tag.equals("ol")) parent="ol";
if(tag.equals("li")){
if(parent.equals("ul")){
if(first){
output.append("/n/t•");
first= false;
}else{
first = true;
}
}
else{
if(first){
output.append("/n/t"+index+". ");
first= false;
index++;
}else{
first = true;
}
}
}
}
}
y para mostrar el texto ...
myTextView.setText(Html.fromHtml("<ul><li>I am an Android developer</li><li>Another Item</li></ul>", null, new MyTagHandler()));
[Editar]
Kuitsi también ha publicado una biblioteca realmente buena que hace lo mismo:
Lo obtuve de este enlace SO .
Si solo necesita formatear una lista, manténgala simple y copie / pegue un carácter Unicode en su TextView para lograr el mismo resultado.
• Carácter Unicode ''BULLET'' (U + 2022)
Simplemente puede reemplazar el "li" con unicodes
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
if (tag.equalsIgnoreCase("li")) {
if (opening) {
output.append("/u2022 ");
} else {
output.append("/n");
}
}
}
Tuve el problema, siempre tuve una línea vacía después de una lista con la solución @Kuitsis. Agregué algunas líneas en handleTag () y ahora las líneas vacías se han ido:
@Override
public void handleTag(final boolean opening, final String tag, final Editable output, final XMLReader xmlReader) {
if (UL_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <ul>
lists.push(new Ul());
} else { // handle </ul>
lists.pop();
if (output.length() > 0 && output.charAt(output.length() - 1) == ''/n'') {
output.delete(output.length() - 1, output.length());
}
}
} else if (OL_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <ol>
lists.push(new Ol()); // use default start index of 1
} else { // handle </ol>
lists.pop();
if (output.length() > 0 && output.charAt(output.length() - 1) == ''/n'') {
output.delete(output.length() - 1, output.length());
}
}
} else if (LI_TAG.equalsIgnoreCase(tag)) {
if (opening) { // handle <li>
lists.peek().openItem(output);
} else { // handle </li>
lists.peek().closeItem(output, lists.size());
}
} else {
Log.d("TagHandler", "Found an unsupported tag " + tag);
}
}
Una pequeña solución al código de Aman Guatam. La función anterior tiene el problema de representar el carácter de línea nueva. Por ejemplo: si antes de la etiqueta <li>
es una etiqueta <p>
, se representan 2 caracteres de nueva línea. Aquí está el código actualizado:
import org.xml.sax.XMLReader;
import android.text.Editable;
import android.text.Html.TagHandler;
public class ListTagHandler implements TagHandler {
boolean first = true;
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
// TODO Auto-generated method stub
if (tag.equals("li")) {
char lastChar = 0;
if (output.length() > 0)
lastChar = output.charAt(output.length() - 1);
if (first) {
if (lastChar == ''/n'')
output.append("/t• ");
else
output.append("/n/t• ");
first = false;
} else {
first = true;
}
}
}
}
Vine aquí buscando implementaciones de TagHandler. Las respuestas de Truong Nguyen y Aman Guatam son muy buenas, pero necesitaba una versión mixta de ambas: necesitaba mi solución para no sobreformarla y poder resolver las etiquetas <ol>
, ya que estoy analizando algo así como el <h3>title</h3><ol><li>item</li><li>item</li><li>item</li></ol>
.
Aquí está mi solución.
import org.xml.sax.XMLReader;
import android.text.Editable;
import android.text.Html.TagHandler;
public class MyTagHandler implements TagHandler {
boolean first = true;
String parent = null;
int index = 1;
public void handleTag(final boolean opening, final String tag,
final Editable output, final XMLReader xmlReader) {
if (tag.equals("ul")) {
parent = "ul";
index = 1;
} else if (tag.equals("ol")) {
parent = "ol";
index = 1;
}
if (tag.equals("li")) {
char lastChar = 0;
if (output.length() > 0) {
lastChar = output.charAt(output.length() - 1);
}
if (parent.equals("ul")) {
if (first) {
if (lastChar == ''/n'') {
output.append("/t• ");
} else {
output.append("/n/t• ");
}
first = false;
} else {
first = true;
}
} else {
if (first) {
if (lastChar == ''/n'') {
output.append("/t" + index + ". ");
} else {
output.append("/n/t" + index + ". ");
}
first = false;
index++;
} else {
first = true;
}
}
}
}
}
Tenga en cuenta que, dado que estamos restableciendo el valor del índice cada vez que se inicia una nueva lista, NO funcionará si anida listas como en <ol><li>1<ol><li>1.1</li><li>1.2</li></ol><li>2</li></ol>
- 1
- 1.1
- 1.2
- 2
Con ese código, obtendría 1, 1, 2, 3
lugar de 1, 1, 2, 2
.
esto es una confirmación de lo que ha declarado Kassim. hay fragmentación. Encontré cómo resolver esto. Tengo que cambiar el nombre de <li>
y ul a una etiqueta personalizada. asi que:
myHTML.replaceAll("</ul>","</customTag>").replaceAll("<ul>","<customTag>");
//likewise for li
luego en mi controlador puedo buscar esa etiqueta personalizada (que no hace nada) y hacer que haga algo.
//now my handler can handle the customtags. it was ignoring them after nougat.
public class UlTagHandler implements Html.TagHandler {
//for ul in nougat and up this tagHandler is completely ignored
@Override
public void handleTag(boolean opening, String tag, Editable output,
XMLReader xmlReader) {
if (tag.equals("customtag2") && opening)
output.append("/n/t/u25CF/t");
if (tag.equals("customtag2") && !opening)
output.append("/n");
}
}
esto debería hacer que funcione para todas las versiones de Android.
ADVERTENCIA
a partir del 10 de febrero de 2016, android.text.Html
realmente admite etiquetas li
y ul
y utiliza un new BulletSpan()
básico, lo que significa que en las últimas versiones de Android se Html.TagHandler
soluciones Html.TagHandler
publicadas aquí.
asegúrese de que su código maneje este cambio en caso de que esté esperando un BulletSpan con un espacio más grande que el predeterminado, tendrá que tener algún tipo de solución que haga un descubrimiento / reemplazo de los tramos
La respuesta de Lord Voldermort es un buen punto de partida. Sin embargo, ol
etiqueta ol
para mostrar la lista ordenada 1. 2. 3. ....
lugar de viñetas. Además, las etiquetas anidadas necesitan un manejo especial para funcionar correctamente.
En mi código, he mantenido stack (parentList) para realizar un seguimiento de las etiquetas ul
y ol
abiertas y cerradas, y también para conocer la etiqueta abierta actual. Además, levelWiseCounter
se usa para mantener conteos diferentes en caso de etiquetas ol
anidadas.
myTextView.setText(Html.fromHtml("your string", null, new CustomTagHandler()));
. . .
private static class CustomTagHandler implements TagHandler
{
int level = 0;
private LinkedList<Tag> parentList = new LinkedList<DetailFragment.CustomTagHandler.Tag>();
private HashMap<Integer, Integer> levelWiseCounter = new HashMap<Integer, Integer>();
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader)
{
if (tag.equalsIgnoreCase("ul") || tag.equalsIgnoreCase("ol"))
{
if (opening)
{
if (tag.equalsIgnoreCase("ul"))
{
parentList.push(Tag.UL);
}
else
{
parentList.push(Tag.OL);
}
level++;
}
else
{
if (!parentList.isEmpty())
{
parentList.pop();
//remove counter at that level, in any present.
levelWiseCounter.remove(level);
}
level--;
if (level < 0)
{
level = 0;
}
}
}
else if (tag.equalsIgnoreCase("li"))
{
if (opening && level > 0)
{
//new line check
int length = output.toString().length();
if (length > 0 && (output.toString().charAt(length - 1) == ''/n''))
{
}
else
{
output.append("/n");
}
//add tabs as per current level of li
for (int i = 0; i < level; i++)
{
output.append("/t");
}
// append dot or numbers based on parent tag
if (Tag.UL == parentList.peek())
{
output.append("•");
}
else
{
//parent is OL. Check current level and retreive counter from levelWiseCounter
int counter = 1;
if (levelWiseCounter.get(level) == null)
{
levelWiseCounter.put(level, 1);
}
else
{
counter = levelWiseCounter.get(level) + 1;
levelWiseCounter.put(level, counter);
}
output.append(padInt(counter) + ".");
}
//trailing tab
output.append("/t");
}
}
}
/**
* Add padding so that all numbers are aligned properly. Currently supports padding from 1-99.
*
* @param num
* @return
*/
private static String padInt(int num)
{
if (num < 10)
{
return " " + num;
}
return "" + num;
}
private enum Tag
{
UL, OL
}
}