Définir du texte TextView à partir d'une ressource de chaîne au format HTML en XML

195

J'ai des chaînes fixes à l'intérieur de moi strings.xml, quelque chose comme:

<resources>
    <string name="somestring">
        <B>Title</B><BR/>
        Content
    </string>
</resources>

et dans ma mise en page, j'en ai un TextViewque j'aimerais remplir avec la chaîne au format html.

<TextView android:id="@+id/formattedtext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/htmlstring"/>

si je fais cela, le contenu de formattedtextest juste le contenu somestringde toute balise html et donc non formaté.

Je sais qu'il est possible de définir le texte formaté par programmation avec

.setText(Html.fromHtml(somestring));

car je l'utilise dans d'autres parties de mon programme où il fonctionne comme prévu.

Pour appeler cette fonction, j'ai besoin d'un Activity, mais pour le moment ma mise en page n'est qu'une simple vue plus ou moins statique en XML simple et je préfère le laisser de cette façon, pour me sauver de la surcharge de création d'un Activityjuste pour en définir texte.

Suis-je en train d'oublier quelque chose d'évident? N'est-ce pas possible du tout? Toute aide ou solution de contournement est la bienvenue!

Edit: Je viens d'essayer certaines choses et il semble que le formatage HTML en xml ait quelques contraintes:

  • les balises doivent être écrites en minuscules

  • certaines balises mentionnées ici ne fonctionnent pas, par exemple <br/>(il est possible d'utiliser à la \nplace)

slup
la source
1
Cela fait longtemps que je sais, mais j'ai pu utiliser <br> et non \ n pour une nouvelle ligne en utilisant le HTML pour un TextView.
Tam
2
Cela peut-il fonctionner à partir de seulement xml? J'ai une petite prime sur la réponse. Je ne prendrais pas comme réponses factuelles à ce stade, je les ai déjà codées.
danny117
1
Je trouve intéressant que personne n'ait répondu à la question. L'OP indique qu'il sait comment le faire avec fromHtml (), mais veut le faire directement dans le fichier de mise en page (bien que les raisons ne soient pas bonnes ... vous avez toujours une activité / un contexte disponible si vous dessinez sur l'écran). Aucune des réponses ne plonge non plus dans les effets des balises d'ancrage.
lilbyrdie

Réponses:

481

Juste au cas où quelqu'un trouverait cela, il existe une alternative plus agréable qui n'est pas documentée (je l'ai trébuché après avoir cherché pendant des heures, et je l'ai finalement trouvée dans la liste des bogues pour le SDK Android lui-même). Vous POUVEZ inclure du HTML brut dans strings.xml, tant que vous l'enveloppez dans

<![CDATA[ ...raw html... ]]>

Exemple:

<string name="nice_html">
<![CDATA[
<p>This is a html-formatted string with <b>bold</b> and <i>italic</i> text</p>
<p>This is another paragraph of the same string.</p>
]]>
</string>

Ensuite, dans votre code:

TextView foo = (TextView)findViewById(R.id.foo);
foo.setText(Html.fromHtml(getString(R.string.nice_html)));

À mon humble avis, il est plus agréable de travailler avec plusieurs ordres de grandeur :-)

Bitbang3r
la source
26
Juste pour ajouter, vous pouvez également utiliser des apostrophes / apostrophes d'échappement dans le bloc CDATA, de sorte que vous pouvez avoir des choses comme <b> can \ 't </b> au lieu de l'infiniment plus laid <b> can & apos; t < / b>
Bitbang3r
5
Est-ce que cela fonctionne toujours? Je viens de l'essayer et il affiche littéralement les <p> et </p>.
Peri Hartman
1
@PeriHartman Avez-vous également fait le Html.fromHtml(getString(R.string.nice_html))morceau? :)
asynchrone
1
Où TextView foo = (TextView) findViewById (R.id.foo); foo.setText (Html.fromHtml (getString (R.string.nice_html))); besoin d'aller?
RustyIngles
2
Existe-t-il un moyen d'éviter "Html.fromHtml"?
développeur Android
127

Comme la meilleure réponse ici suggère quelque chose de mal (ou du moins trop compliqué), je pense que cela devrait être mis à jour, bien que la question soit assez ancienne:

Lorsque vous utilisez des ressources String dans Android, il vous suffit d'appeler à getString(...)partir du code Java ou d'utiliser android:text="@string/..."dans votre mise en page XML.

Même si vous souhaitez utiliser le balisage HTML dans vos chaînes, vous n'avez pas besoin de beaucoup changer:

Les seuls personnages que vous devez échapper dans vos ressources String sont:

  • guillemet double: "devient\"
  • guillemet simple: 'devient\'
  • esperluette: &devient &#38;ou&amp;

Cela signifie que vous pouvez ajouter votre balisage HTML sans échapper aux balises:

<string name="my_string"><b>Hello World!</b> This is an example.</string>

Cependant, pour être sûr, vous devez uniquement utiliser <b>, <i>et <u>comme ils sont répertoriés dans la documentation.

Si vous souhaitez utiliser vos chaînes HTML à partir de XML , continuez à utiliser android:text="@string/...", cela fonctionnera bien.

La seule différence est que, si vous souhaitez utiliser vos chaînes HTML à partir du code Java , vous devez utiliser à la getText(...)place de getString(...)maintenant, car le premier conserve le style et le second le supprimera.

C'est aussi simple que ça. Pas de CDATA, non Html.fromHtml(...).

Vous aurez seulement besoin Html.fromHtml(...)si vous avez encodez vos caractères spéciaux en HTML balisage. Utilisez-le avec getString(...)alors. Cela peut être nécessaire si vous souhaitez transmettre la chaîne à String.format(...).

Tout cela est également décrit dans la documentation .

Éditer:

Il n'y a pas de différence entre getText(...)HTML non échappé (comme je l'ai proposé) ou CDATAsections et Html.fromHtml(...).

Voir le graphique suivant pour une comparaison:

entrez la description de l'image ici

croasser
la source
Le mien l'enlève. J'utilise le code suivant:getResources().getText(R.string.codename)
Si8
3
Afin de mieux aider, j'aurais besoin de voir les extraits Java / XML. Mais comme je l' ai écrit: Vous êtes sûr que si vous utilisez <b>, <i>, <u>. Les autres balises ne sont pas toujours prises en charge.
caw
1
Votre réponse fonctionne et est simple. Mettez simplement votre chaîne dans strings.xml, avec les balises html souhaitées, et référencez-la à partir de votre fichier xml de mise en page. J'ai utilisé la balise <sup>.
Peri Hartman, le
1
La vôtre est une autre solution, pas une alternative à l'autre car elle ne prend pas en charge toutes les balises, comme l'autre. Je ne vois aucun avantage dans cette solution lorsque l'autre est très simple.
mobilepotato7
1
Comme je l'ai expérimenté en utilisant "CDATA", j'ai un problème, quelque chose comme ceci par exemple: <! [CDATA [... HTML ...]]> qui ont 22 lettres et une partie html en a 10. donc si vous utilisez HTML.fromhtml ( getstring (...)) votre texte s'affichera correctement mais le contenu du texte nécessite 22 espaces de lettres. J'ai utilisé dans listview et vu des espaces de mauvaises herbes. donc gettext () est MIEUX.
David
16

Échappez à vos balises HTML ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
ekawas
la source
C'est ce que disent les docs: developer.android.com/intl/zh-TW/guide/topics/resources/… mais est-ce suffisant pour TextViewafficher HTML?
Macarse
3
J'ai testé cela, et si vous l'utilisez à partir du code source java, ça va. Mais si vous associez votre texte directement à partir de la mise en page XML, les balises sont affichées dans la vue texte (par exemple <B> Titre </B> ...)
ZoltanF
Pour afficher le texte dans une vue, utilisez spécifiquement la classe [ developer.android.com/reference/android/text/Html.html]fromHTML() .
ekawas
@ZoltanF a raison, en utilisant android: text = "" à partir d'une mise en page avec le HTML affichera les balises dans la chaîne.
Andrew Mackenzie
1
Si vous souhaitez utiliser la chaîne HTML directement à partir de XML, vous ne pouvez pas coder les caractères spéciaux HTML dans la chaîne. Cependant, si vous souhaitez utiliser la chaîne du code via, Html.fromHTML()vous devez encoder les caractères spéciaux. Étrange!
caw
11

Android n'a pas de spécification pour indiquer le type de chaîne de ressource (par exemple, text / plain ou text / html). Il existe cependant une solution de contournement qui permettra au développeur de le spécifier dans le fichier XML.

  1. Définissez un attribut personnalisé pour spécifier que l'attribut android: text est html.
  2. Utilisez un TextView sous-classé.

Une fois que vous les avez définis, vous pouvez vous exprimer avec du HTML dans des fichiers xml sans avoir à appeler à nouveau setText (Html.fromHtml (...)). Je suis plutôt surpris que cette approche ne fasse pas partie de l'API.

Cette solution fonctionne dans la mesure où le simulateur de studio Android affiche le texte au format HTML rendu.

entrez la description de l'image ici

res / values ​​/ strings.xml (la ressource de chaîne au format HTML)

<resources>
<string name="app_name">TextViewEx</string>
<string name="string_with_html"><![CDATA[
       <em>Hello</em> <strong>World</strong>!
 ]]></string>
</resources>

layout.xml (uniquement les parties pertinentes)

Déclarez l'espace de noms d'attribut personnalisé et ajoutez l'attribut android_ex: isHtml. Utilisez également la sous-classe de TextView.

<RelativeLayout
...
xmlns:android_ex="http://schemas.android.com/apk/res-auto"
...>

<tv.twelvetone.samples.textviewex.TextViewEx
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/string_with_html"
    android_ex:isHtml="true"
    />
 </RelativeLayout>

res / values ​​/ attrs.xml (définir les attributs personnalisés pour la sous-classe)

 <resources>
<declare-styleable name="TextViewEx">
    <attr name="isHtml" format="boolean"/>
    <attr name="android:text" />
</declare-styleable>
</resources>

TextViewEx.java (la sous-classe de TextView)

 package tv.twelvetone.samples.textviewex;

 import android.content.Context;
 import android.content.res.TypedArray;
 import android.support.annotation.Nullable;
 import android.text.Html;
 import android.util.AttributeSet;
 import android.widget.TextView;

public TextViewEx(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextViewEx, 0, 0);
    try {
        boolean isHtml = a.getBoolean(R.styleable.TextViewEx_isHtml, false);
        if (isHtml) {
            String text = a.getString(R.styleable.TextViewEx_android_text);
            if (text != null) {
                setText(Html.fromHtml(text));
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        a.recycle();
    }
}
}
Steven Spungin
la source
Cette approche sera meilleure, si l'application utilise des chaînes au format HTML à plusieurs endroits au lieu d'appeler HTML.fromHtml à chaque endroit. L'application elle-même aura deux vues, une pour la normale et une pour le HTML.
Manju
10

Dernière mise à jour:

Html.fromHtml(string);// obsolète après les versions d'Android N ..

Le code suivant prend en charge les versions Android N et supérieures ...

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
textView.setText(Html.fromHtml(yourHtmlString,Html.FROM_HTML_MODE_LEGACY));
}

else 
{
textView.setText(Html.fromHtml(yourHtmlString));
}
Ranjith Kumar
la source
3
  String termsOfCondition="<font color=#cc0029>Terms of Use </font>";
  String commma="<font color=#000000>, </font>";
  String privacyPolicy="<font color=#cc0029>Privacy Policy </font>";
  Spanned text=Html.fromHtml("I am of legal age and I have read, understood, agreed and accepted the "+termsOfCondition+commma+privacyPolicy);
        secondCheckBox.setText(text);
Dishant Kawatra
la source
2

J'ai un autre cas où je n'ai aucune chance de mettre CDATA dans le xml car je reçois la chaîne HTML d'un serveur.

Voici ce que j'obtiens d'un serveur:

<p>The quick brown&nbsp;<br />
fox jumps&nbsp;<br />
 over the lazy dog<br />
</p>

Cela semble plus compliqué mais la solution est beaucoup plus simple.

private TextView textView;

protected void onCreate(Bundle savedInstanceState) { 
.....
textView = (TextView) findViewById(R.id.text); //need to define in your layout
String htmlFromServer = getHTMLContentFromAServer(); 
textView.setText(Html.fromHtml(htmlFromServer).toString());

}

J'espère que ça aide!
Linh

Linh Lino
la source
4
où est l'implémentation de la fonction getHTMLContentFromAServer ()
Pallavi