Comment afficher du HTML dans TextView?

758

J'ai du HTML simple :

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

Je souhaite afficher le texte de style HTML dans celui-ci TextView. Comment faire ça?

UMAR
la source
7
Voulez-vous afficher les balises ou les omettre?
DerMike
1
consultez ce lien pour un exemple de travail javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal
1
Si vous recherchez la solution obsolète, c'est juste ici stackoverflow.com/questions/37904739/…
crgarridos

Réponses:

1353

Vous devez utiliser Html.fromHtml()pour utiliser HTML dans vos chaînes XML. Le simple fait de référencer une chaîne avec HTML dans votre mise en page XML ne fonctionnera pas.

Voici ce que vous devez faire:

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>"));
}
Johnny Five
la source
7
h2par définition crée beaucoup de marge autour de lui. et pvient également avec une certaine marge. si vous ne voulez pas l'écart, vous voudrez peut-être envisager d'utiliser d'autres éléments html.
David Hedlund
10
Kostadin, vous pouvez mettre des balises en XML, il vous suffit de les mettre entre crochets CDATA.
Gerard
3
Pour ceux qui souhaitent que cela fonctionne avec les balises ol / ul / li, consultez cette solution: stackoverflow.com/a/3150456/1369016
Tiago
14
Ça devrait l'être android.text.Html.fromHtml. Je sais que la plupart des IDE le corrigent pour vous, mais pour plus de lisibilité, il est plus agréable de connaître les noms des packages.
Martin
14
@Martin je ne dirais pas pour la lisibilité mais plutôt pour l'exhaustivité . Les noms pleinement qualifiés de l'OMI utilisés directement dans un code comme celui-ci sont moins lisibles que les noms courts. Mais je suis d'accord avec vous sur le fait qu'une réponse comme celle-ci devrait fournir le package (sur une note annexe), dont le point du lien ici;)
Joffrey
76

setText (Html.fromHtml (bodyData)) est obsolète après l'api 24. Maintenant, vous devez faire ceci:

 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));
 }
Shohan Ahmed Sijan
la source
4
Pourquoi utilise FROM_HTML_MODE_LEGACY dans l'API 24+?
galcyurio
64

Jetez un oeil à ce sujet: https://stackoverflow.com/a/8558249/450148

C'est assez bien aussi !!

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

Cela ne fonctionne que pour quelques balises.

Felipe Micaroni Lalli
la source
12
Existe-t-il une liste de balises prises en charge par cette méthode?
mente
23
@mente Selon les codes source : <a>, <b>, <big>, <blockquote>, <br>, <cite>, <dfn> <div align = "...">, <em>, < font size = "..." color = "..." face = "..."> <h1-6>, <i>, <img src = "...">, <p>, <small > <strike>, <strong>, <sub>, <sup>, <tt>, <u> (source: dzone.com/snippets/how-display-html-android )
JerabekJakub
@JerabekJakub mais faites attention, si vous allez gérer img, vous devez implémenter Html.ImageGetter.
MiguelHincapieC
@ 0mahc0 quand on implémente img est-il possible de régler la taille?
Joh
1
@Joh oui c'est possible. Lorsque vous implémentez .ImageGetter, il existe une méthode appelée getDrawable (String source). Si vous avez besoin d'aide, créez une question et identifiez-moi, je vais vous donner un exemple;)
MiguelHincapieC
41

Si vous voulez pouvoir le configurer via xml sans aucune modification dans le code java, cette idée peut vous être utile. Vous appelez simplement init du constructeur et définissez le texte en 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"/>
1299412
la source
1
Qu'est-ce que '...'. Veuillez clarifier
GilbertS
25

Si vous essayez d'afficher du HTML à partir d'un ID de ressource de chaîne, le formatage peut ne pas s'afficher à l'écran. Si cela vous arrive, essayez plutôt d'utiliser des balises 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));

Voir cet article pour plus de détails.

Phileo99
la source
Merci, cela l'a fait pour moi - en utilisant l'API 23.
XMAN
24

Le code ci-dessous a donné le meilleur résultat pour moi.

TextView myTextview = (TextView) findViewById(R.id.my_text_view);
htmltext = <your html (markup) character>;
Spanned sp = Html.fromHtml(htmltext);
myTextview.setText(sp);
Rajiv Manivannan
la source
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());
Pedro
la source
comment changez-vous la couleur de l'ancre?
EdmundYeung99
android: textColorLink = "color"
Pedro
cela colorera la totalité du texte en rouge, mais si je ne veux que les balises d'ancrage, je dois envelopper la balise <a> avec des balises <et y ajouter de la couleur
EdmundYeung99
11

Si vous voulez simplement afficher du texte html et que vous n'en avez pas vraiment besoin TextView, prenez-en un WebViewet utilisez-le comme suit:

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

Cela ne vous limite pas non plus à quelques balises html.

prom85
la source
2
Bien que ce soit un moyen très utile de contourner l'ensemble restreint de balises html, pris en charge par TextView, il présente l'inconvénient de ne pas bien fonctionner avec layout_height="wrap_content". Vous devrez plutôt définir une hauteur explicite ou match_parent.
Ridcully
3
la visualisation Web est très lente
Jackky777
11

La meilleure approche pour utiliser les sections CData pour la chaîne dans le fichier strings.xml pour obtenir un affichage réel du contenu html dans TextView l'extrait de code ci-dessous vous donnera une idée juste.

//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 section CData dans le texte de chaîne conserve les données de balise html intact même après avoir formaté le texte à l'aide de la méthode String.format. Ainsi, Html.fromHtml (str) fonctionne correctement et vous verrez le texte en gras dans le message de bienvenue.

Production:

Bienvenue dans votre magasin d'applications musicales préféré. Connecté en tant que: nom d'utilisateur

Rajendhiran Easu
la source
Merci, cela l'a fait pour moi - en utilisant l'API 23.
XMAN
merci, vous avez sauvé ma journée :) Juste un petit ajout: nous devons ajouter cette vérification au code ci-dessus: if (Build.VERSION.SDK_INT> = Build.VERSION_CODES.N) {// pour 24 api et plus textView.setText ( Html.fromHtml (welcomStr, Html.FROM_HTML_OPTION_USE_CSS_COLORS)); } else {// ou pour une ancienne api textView.setText (Html.fromHtml (welcomStr)); }. La valeur pour le 2ème indicateur de paramètre pour l'API> = 24, peut être n'importe quoi selon l'exigence.
AndroidGuy
6

Je voudrais également suggérer le projet suivant: https://github.com/NightWhistler/HtmlSpanner

L'utilisation est presque la même que celle du convertisseur Android par défaut:

(new HtmlSpanner()).fromHtml()

Je l'ai trouvé après avoir déjà commencé par la propre implémentation du convertisseur html en spannable, car Html.fromHtml standard ne fournit pas assez de flexibilité sur le contrôle du rendu et même aucune possibilité d'utiliser des polices personnalisées à partir de ttf

Fedotchenco Denis
la source
J'obtiens l'erreur suivante: Erreur: (80, 13) Échec de la résolution: com.osbcp.cssparser: cssparser: 1.5 Comment résoudre ce problème?
Araju
6

Je sais que cette question est ancienne. D'autres réponses suggèrent ici la Html.fromHtml()méthode. Je vous suggère d'utiliser à HtmlCompat.fromHtml()partir du androidx.core.text.HtmlCompatpackage. Comme il s'agit d'une version rétrocompatible deHtml classe.

Exemple de code:

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

De cette façon, vous pouvez éviter la vérification de la version de l'API Android et c'est facile à utiliser (solution à une seule ligne).

Shashanth
la source
En quoi est-ce différent de l'ancien méthot? À quoi sert le mode html?
user1209216
1
Je cherchais quelque chose comme ça. Merci :)
Subhrajyoti Sen
5

Utilisation simple Html.fromHtml("html string"). Cela fonctionnera. Si la chaîne a des balises comme cela, des <h1>espaces viendront. Mais nous ne pouvons pas éliminer ces espaces. Si vous souhaitez toujours supprimer les espaces, vous pouvez supprimer les balises de la chaîne, puis transmettre la chaîne à la méthode Html.fromHtml("html string");. De manière générale, ces chaînes proviennent également du serveur (dynamique) mais pas souvent, s'il est préférable de transmettre la chaîne telle quelle à la méthode plutôt que de supprimer les balises de la chaîne.

nole
la source
4
String value = html value ....
mTextView.setText(Html.fromHtml(value),TextView.BufferType.SPANNABLE)
samuel gildas
la source
4

Créez une méthode globale comme:

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

Vous pouvez également l'utiliser dans votre activité / fragment comme:

text_view.setText(stripHtml(htmlText));
Shylendra Madda
la source
3

J'ai implémenté cela en utilisant la vue Web. Dans mon cas, je dois charger l'image de l'URL avec le texte en mode texte et cela fonctionne pour moi.

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);
Tueur
la source
Pour un affichage correct de UTF-8, vous devez définir le type MIME sur "text / html; charset = UTF-8".
shawkinaw
3

Il a été suggéré à travers diverses réponses d'utiliser la classe de framework Html comme suggéré ici, mais malheureusement, cette classe a un comportement différent dans différentes versions d'Android et divers bogues non résolus , comme démontré dans les problèmes 214637 , 14778 , 235128 et 75953 .

Vous souhaiterez donc peut-être utiliser une bibliothèque de compatibilité pour normaliser et rétroporter la classe Html sur les versions Android, ce qui inclut davantage de rappels pour les éléments et le style:

Projet Github HtmlCompat

Bien qu'elle soit similaire à la classe Html du framework, certaines modifications de signature étaient nécessaires pour autoriser plus de rappels. Voici l'exemple de la page 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);
Paul Lammertsma
la source
@MartijnPieters La réponse précédemment fermée était un doublon d'une réponse à cette question en relation avec la dépréciation d'une méthode cadre . J'ai développé la raison pour laquelle l'utilisation d'une bibliothèque de compatibilité serait une meilleure approche. Je ne pense pas qu'il soit raisonnable de signaler l'une ou l'autre question comme des doublons les uns des autres car ils sont clairement différents.
Paul Lammertsma
2

Chaque fois que vous écrivez une vue de texte personnalisée, la fonctionnalité de base du texte HTML sera supprimée de certains appareils.

Nous devons donc suivre les étapes supplémentaires pour faire fonctionner

public class CustomTextView extends TextView {

    public CustomTextView(..) {
        // other instructions
        setText(Html.fromHtml(getText().toString()));
    }
}
Vinayak
la source
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()));
    }
 }
}

mise à jour de la réponse ci-dessus

Isaac Sekamatte
la source
1

Utilisez le code ci-dessous pour obtenir la solution:

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

Méthode d'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;
}
Somesh Kumar
la source
1

Création d' extensions Kotlin pour convertir le HTML à partir de String -

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

Puis-je suggérer une solution quelque peu hacky mais toujours géniale! J'ai eu l'idée de cet article et je l'ai adaptée pour Android. Fondamentalement, vous utilisez un WebViewet insérez le code HTML que vous souhaitez afficher et modifier dans une balise div modifiable. De cette façon, lorsque l'utilisateur appuie sur leWebView le clavier apparaît et permet l'édition. Ils vous ajoutent juste du JavaScript pour récupérer le HTML édité et le tour est joué!

Voici le code:

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

Et voici le composant en tant que Gist.

Remarque: Je n'avais pas besoin du rappel de changement de hauteur de la solution d'origine, il manque donc ici, mais vous pouvez facilement l'ajouter si nécessaire.

AX
la source
0

Si vous utilisez des androidx.classes * dans votre projet, vous devez utiliser HtmlCompat.fromHtml(text, flag). La source de la méthode est:

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

C'est mieux que Html.fromHtml car il y a moins de code, une seule ligne et la façon recommandée de l'utiliser.

Panda
la source
0

Vous pouvez utiliser une fonction d'extension Kotlin simple comme ceci:

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

Et l'utilisation:

textViewMessage.setHtmlText("Message: <b>Hello World</b>")
seyfullah.bilgin
la source
0

Utilisez simplement:

String variable="StackOverflow";
textView.setText(Html.fromHtml("<b>Hello : </b>"+ variable));
Sumit Shukla
la source