Come visualizzare HTML in TextView?


757

Ho un semplice HTML :

<h2>Title</h2><br>
<p>description here</p>

Voglio visualizzare il testo in stile HTML in esso TextView. Come fare questo?


7
Vuoi visualizzare i tag o ometterli?
DerMike,

1
controlla questo link per un esempio funzionante javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal

1
Se siete alla ricerca di una soluzione di deprecato, è giusto qui stackoverflow.com/questions/37904739/...~~V~~singular~~3rd
crgarridos

Risposte:


1352

È necessario utilizzare Html.fromHtml()per utilizzare HTML nelle stringhe XML. Il semplice riferimento a una stringa con HTML nel layout XML non funzionerà.

Questo è ciò che dovresti fare:

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>"));
}

7
h2per definizione crea molto margine attorno a se stesso. e pviene anche con un certo margine. se non vuoi il divario, potresti prendere in considerazione l'uso di altri elementi html.
David Hedlund,

10
Kostadin, puoi inserire tag in XML, devi solo avvolgerli tra parentesi CDATA.
Gerard,

3
Per coloro che vogliono che funzioni con i tag ol / ul / li, dai un'occhiata a questa soluzione: stackoverflow.com/a/3150456/1369016
Tiago,

14
Questo dovrebbe essere android.text.Html.fromHtml. So che la maggior parte degli IDE lo risolverà per te, ma per leggibilità è meglio conoscere i nomi dei pacchetti.
Martin,

14
@Martin Non direi per leggibilità ma piuttosto per esaustività . I nomi pienamente qualificati IMO utilizzati direttamente nel codice come questo sono meno leggibili dei nomi brevi. Ma sono d'accordo con te sul fatto che una risposta come questa dovrebbe fornire il pacchetto (in una nota a margine), che il punto del link qui;)
Joffrey,

76

setText (Html.fromHtml (bodyData)) è deprecato dopo api 24. Ora devi fare questo:

 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
      tvDocument.setText(Html.fromHtml(bodyData,Html.FROM_HTML_MODE_LEGACY));
 } else {
      tvDocument.setText(Html.fromHtml(bodyData));
 }

4
Perché utilizza FROM_HTML_MODE_LEGACY in API 24+?
galcyurio,

64

Dai un'occhiata a questo: https://stackoverflow.com/a/8558249/450148

È anche abbastanza buono !!

<resource>
    <string name="your_string">This is an <u>underline</u> text demo for TextView.</string>
</resources>

Funziona solo con pochi tag.


12
Esiste un elenco di tag supportati da questo metodo?
mente,

23
@mente Secondo i codici sorgente : <a>, <b>, <big>, <blockquote>, <br>, <cite>, <dfn> <div align = "...">, <em>, < font size = "..." color = "..." face = "..."> <h1-6>, <i>, <img src = "...">, <p>, <piccolo > <strike>, <strong>, <sub>, <sup>, <tt>, <u> (fonte: dzone.com/snippets/how-display-html-android )
JerabekJakub

@JerabekJakub ma stai attento, se hai intenzione di gestire img devi implementare Html.ImageGetter.
MiguelHincapieC,

@ 0mahc0 quando si implementa img è possibile impostare la dimensione?
Joh,

1
@Joh sì, è possibile. Quando stai implementando .ImageGetter, esiste un metodo chiamato getDrawable (sorgente String). Se hai bisogno di ulteriore aiuto, crea una domanda e
taggami

41

Se vuoi essere in grado di configurarlo tramite XML senza alcuna modifica nel codice Java, potresti trovare utile questa idea. Basta chiamare init dal costruttore e impostare il testo come html

public class HTMLTextView extends TextView {
    ... constructors calling init...
    private void init(){
       setText(Html.fromHtml(getText().toString()));
    }    
}

xml:

<com.package.HTMLTextView
android:text="@string/about_item_1"/>

1
Che cos'è "...". Per favore, chiarisci
GilbertS

25

Se si sta tentando di mostrare HTML da un ID risorsa stringa, la formattazione potrebbe non essere visualizzata sullo schermo. Se ciò accade, prova invece a utilizzare i tag CDATA:

strings.xml:
<string name="sample_string"><![CDATA[<h2>Title</h2><br><p>Description here</p>]]></string>

...

MainActivity.java:
text.setText(Html.fromHtml(getString(R.string.sample_string));

Vedi questo post per ulteriori dettagli.


Grazie, l'ho fatto per me usando API 23.
XMAN

24

Il codice seguente ha dato il miglior risultato per me.

TextView myTextview = (TextView) findViewById(R.id.my_text_view);
htmltext = <your html (markup) character>;
Spanned sp = Html.fromHtml(htmltext);
myTextview.setText(sp);

13
String value = "<html> <a href=\"http://example.com/\">example.com</a> </html>";
    SiteLink= (TextView) findViewById(R.id.textViewSite);
    SiteLink.setText(Html.fromHtml(value));
    SiteLink.setMovementMethod(LinkMovementMethod.getInstance());

come si cambia il colore dell'ancora?
EdmundYeung99,

android: textColorLink = "color"
Pedro

questo colora l'intera vista di testo in rosso, ma se voglio solo i tag di ancoraggio, devo avvolgere il tag <a> con i tag <font> e aggiungere il colore lì
dentro

11

Se vuoi solo mostrare del testo html e non hai davvero bisogno di a TextView, allora prendi a WebViewe usalo come segue:

String htmlText = ...;
webview.loadData(htmlText , "text/html; charset=UTF-8", null);

Questo non ti limita nemmeno ad alcuni tag html.


2
Mentre questo è un modo molto utile per aggirare il set limitato di tag HTML, supportato da TextView, ha lo svantaggio che non funziona bene con layout_height="wrap_content". Dovrai invece impostare un'altezza esplicita o match_parent.
Ridcully,

3
la webview è molto lenta
Jackky777,

11

L'approccio migliore per utilizzare le sezioni CData per la stringa nel file strings.xml per ottenere una visualizzazione effettiva del contenuto html in TextView lo snippet di codice seguente ti darà la giusta idea.

//in string.xml file
<string name="welcome_text"><![CDATA[<b>Welcome,</b> to the forthetyroprogrammers blog Logged in as:]]> %1$s.</string>

//and in Java code
String welcomStr=String.format(getString(R.string.welcome_text),username);
tvWelcomeUser.setText(Html.fromHtml(welcomStr));

La sezione CData nel testo della stringa mantiene intatti i dati del tag html anche dopo la formattazione del testo usando il metodo String.format. Quindi, Html.fromHtml (str) funziona bene e vedrai il testo in grassetto nel messaggio di benvenuto.

Produzione:

Benvenuto nel tuo app store musicale preferito. Accesso effettuato come: nome utente


Grazie, l'ho fatto per me, usando API 23.
XMAN

grazie, mi hai salvato la giornata :) Solo una piccola aggiunta: dobbiamo aggiungere questo controllo al codice sopra: if (Build.VERSION.SDK_INT> = Build.VERSION_CODES.N) {// per 24 api e più textView.setText ( Html.fromHtml (welcomStr, Html.FROM_HTML_OPTION_USE_CSS_COLORS)); } else {// o per API precedenti textView.setText (Html.fromHtml (welcomStr)); }. Il valore per il flag del secondo parametro per API> = 24, può essere qualsiasi come da requisito.
AndroidGuy


6

Vorrei anche suggerire il seguente progetto: https://github.com/NightWhistler/HtmlSpanner

L'utilizzo è quasi lo stesso del convertitore Android predefinito:

(new HtmlSpanner()).fromHtml()

L'ho trovato dopo che ho già iniziato con la propria implementazione del convertitore html in spannable, perché lo standard Html.fromHtml non offre sufficiente flessibilità sul controllo del rendering e nemmeno la possibilità di utilizzare caratteri personalizzati da ttf


Ricevo il seguente errore: Errore: (80, 13) Impossibile risolvere: com.osbcp.cssparser: cssparser: 1.5 Come posso risolvere?
Araju,

6

So che questa domanda è vecchia. Altre risposte qui suggeriscono il Html.fromHtml()metodo. Ti suggerisco di usare HtmlCompat.fromHtml()dal androidx.core.text.HtmlCompatpacchetto. Poiché questa è la versione compatibile con le versioni precedenti diHtml classe .

Codice di esempio:

import androidx.core.text.HtmlCompat;
import android.text.Spanned;
import android.widget.TextView;

String htmlString = "<h1>Hello World!</h1>";

Spanned spanned = HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT);

TextView tvOutput = (TextView) findViewById(R.id.text_view_id);

tvOutput.setText(spanned);

In questo modo puoi evitare il controllo della versione dell'API Android ed è facile da usare (soluzione a linea singola).


In che modo è diverso dal vecchio methot? Qual è lo scopo della modalità HTML?
user1209216

1
Stavo cercando qualcosa del genere. Grazie :)
Subhrajyoti Sen

5

Uso semplice Html.fromHtml("html string"). Questo funzionerà. Se la stringa ha tag come <h1>allora verranno gli spazi. Ma non possiamo eliminare quegli spazi. Se si desidera ancora rimuovere gli spazi, è possibile rimuovere i tag nella stringa e quindi passare la stringa al metodo Html.fromHtml("html string");. Inoltre, generalmente queste stringhe provengono dal server (dinamico) ma non spesso, se è il caso di passare la stringa così com'è al metodo piuttosto che provare a rimuovere i tag dalla stringa.


4
String value = html value ....
mTextView.setText(Html.fromHtml(value),TextView.BufferType.SPANNABLE)

4

Crea un metodo globale come:

public static Spanned stripHtml(String html) {
            if (!TextUtils.isEmpty(html)) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    return Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT);
                } else {
                    return Html.fromHtml(html);
                }
            }
            return null;
        }

Puoi anche usarlo nella tua attività / frammento come:

text_view.setText(stripHtml(htmlText));

3

Ho implementato questo utilizzando la visualizzazione Web. Nel mio caso, devo caricare l'immagine dall'URL insieme al testo nella vista testo e questo funziona per me.

WebView myWebView =new WebView(_context);
        String html = childText;
        String mime = "text/html";
        String encoding = "utf-8";
        myWebView.getSettings().setJavaScriptEnabled(true);
        myWebView.loadDataWithBaseURL(null, html, mime, encoding, null);

Per una corretta visualizzazione di UTF-8 è necessario impostare il tipo MIME su "text / html; charset = UTF-8".
Shawkinaw,

3

E 'stato suggerito attraverso varie risposte di utilizzare la Html Framework come suggerito qui, ma purtroppo questa classe ha un comportamento diverso nelle diverse versioni di Android e vari bug non indirizzati, come dimostrato nelle questioni 214637 , 14778 , 235128 e 75953 .

Pertanto, potresti voler utilizzare una libreria di compatibilità per standardizzare e eseguire il backport della classe Html tra le versioni di Android che include più callback per elementi e stile:

Progetto Github HtmlCompat

Sebbene sia simile alla classe Html del framework, sono state necessarie alcune modifiche alla firma per consentire più callback. Ecco l'esempio dalla pagina GitHub:

Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0);
// You may want to provide an ImageGetter, TagHandler and SpanCallback:
//Spanned fromHtml = HtmlCompat.fromHtml(context, source, 0,
//        imageGetter, tagHandler, spanCallback);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(fromHtml);

@MartijnPieters La risposta precedentemente chiusa era un duplicato di una risposta a questa domanda in relazione al deprezzamento di un metodo quadro . Ho ampliato il motivo per cui usare una libreria di compatibilità sarebbe un approccio migliore. Non penso che sia ragionevole contrassegnare entrambe le domande come duplicate l'una dell'altra poiché sono chiaramente diverse.
Paul Lammertsma,

2

Ogni volta che si scrive una visualizzazione di testo personalizzata, la funzione di testo di base HTML verrà svanita da alcuni dei dispositivi.

Quindi dobbiamo fare i seguenti passaggi aggiuntivi per far funzionare

public class CustomTextView extends TextView {

    public CustomTextView(..) {
        // other instructions
        setText(Html.fromHtml(getText().toString()));
    }
}

1
public class HtmlTextView extends AppCompatTextView {

public HtmlTextView(Context context) {
    super(context);
    init();
}

private void init(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        setText(Html.fromHtml(getText().toString(), Html.FROM_HTML_MODE_COMPACT));
    } else {
        setText(Html.fromHtml(getText().toString()));
    }
 }
}

aggiornamento della risposta sopra


1

Utilizzare il codice seguente per ottenere la soluzione:

textView.setText(fromHtml("<Your Html Text>"))

Metodo di utilità

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

1

Create estensioni di Kotlin per convertire HTML da String -

fun String?.toHtml(): Spanned? {
    if (this.isNullOrEmpty()) return null
    return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT)
}

0

Vorrei suggerire una soluzione un po 'confusa ma ancora geniale! Ho preso l'idea da questo articolo e l'ho adattato per Android. Fondamentalmente usi a WebViewe inserisci l'HTML che vuoi mostrare e modificare in un tag div modificabile. In questo modo quando l'utente tocca ilWebView la tastiera appare e consente la modifica. Ti basta aggiungere un po 'di JavaScript per recuperare l'HTML modificato e voilà!

Ecco il codice:

public class HtmlTextEditor extends WebView {

    class JsObject {
        // This field always keeps the latest edited text
        public String text;
        @JavascriptInterface
        public void textDidChange(String newText) {
            text = newText.replace("\n", "");
        }
    }

    private JsObject mJsObject;

    public HtmlTextEditor(Context context, AttributeSet attrs) {
        super(context, attrs);

        getSettings().setJavaScriptEnabled(true);
        mJsObject = new JsObject();
        addJavascriptInterface(mJsObject, "injectedObject");
        setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                loadUrl(
                        "javascript:(function() { " +
                            "    var editor = document.getElementById(\"editor\");" +
                            "    editor.addEventListener(\"input\", function() {" +
                            "        injectedObject.textDidChange(editor.innerHTML);" +
                            "    }, false)" +
                            "})()");
            }
        });
    }

    public void setText(String text) {
        if (text == null) { text = ""; }

        String editableHtmlTemplate = "<!DOCTYPE html>" + "<html>" + "<head>" + "<meta name=\"viewport\" content=\"initial-scale=1.0\" />" + "</head>" + "<body>" + "<div id=\"editor\" contenteditable=\"true\">___REPLACE___</div>" + "</body>" + "</html>";
        String editableHtml = editableHtmlTemplate.replace("___REPLACE___", text);
        loadData(editableHtml, "text/html; charset=utf-8", "UTF-8");
        // Init the text field in case it's read without editing the text before
        mJsObject.text = text;
    }

    public String getText() {
        return mJsObject.text;
    }
}

E ecco il componente come Gist.

Nota: non ho avuto bisogno del callback con cambio di altezza dalla soluzione originale, quindi manca qui, ma è possibile aggiungerlo facilmente se necessario.


0

Se usi androidx.* classi nel tuo progetto, dovresti usare HtmlCompat.fromHtml(text, flag). La fonte del metodo è:

@NonNull public static Spanned fromHtml(@NonNull String source, @FromHtmlFlags int flags) { if (Build.VERSION.SDK_INT >= 24) { return Html.fromHtml(source, flags); } //noinspection deprecation return Html.fromHtml(source); }

È un modo migliore di Html.fromHtml poiché c'è meno codice, solo una riga e il modo consigliato per usarlo.


0

Puoi usare la semplice funzione di estensione di Kotlin in questo modo:

fun TextView.setHtmlText(source: String) {
    this.text = HtmlCompat.fromHtml(source, HtmlCompat.FROM_HTML_MODE_LEGACY)
}

E utilizzo:

textViewMessage.setHtmlText("Message: <b>Hello World</b>")

0

Usa semplicemente:

String variable="StackOverflow";
textView.setText(Html.fromHtml("<b>Hello : </b>"+ variable));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.