web-dev-qa-db-fra.com

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

J'ai quelques chaînes fixes dans mon strings.xml, quelque chose comme:

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

et dans ma mise en page, j'ai un TextView que 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 le fais, le contenu de formattedtext n'est que le contenu de somestring débarrassé de ses balises HTML et donc non formaté.

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

.setText(Html.fromHtml(somestring));

parce que 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 ma mise en page n’est pour le moment qu’une simple vue plus ou moins statique en langage XML simple, et je préférerais la laisser ainsi afin de me préserver de la surcharge de la création. un Activity juste pour définir du texte.

Est-ce que je néglige quelque chose d'évident? N'est-ce pas possible du tout? Toute aide ou solution de rechange est la bienvenue!

Edit: Juste essayé quelques choses et il semble que le formatage HTML en XML a quelques contraintes:

  • les balises doivent être écrites en minuscules

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

191
slup

Au cas où quelqu'un le trouverait, il existe une alternative plus intéressante non documentée (je l'ai trébuché après des heures de recherche et je l'ai finalement trouvée dans la liste des bogues du SDK Androidlui-même). Vous (PEUT inclure du code 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)));

IMHO, il est plus agréable de travailler avec plusieurs ordres de grandeur :-)

467
Bitbang3r

Comme la réponse principale suggère un problème (ou du moins trop compliqué), j'estime que cela devrait être mis à jour, bien que la question soit assez ancienne:

Lorsque vous utilisez des ressources String dans Android, vous devez simplement appeler getString(...) à partir du code Java ou utiliser Android:text="@string/..." dans votre code XML de présentation.

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

Les seuls caractères que vous devez échapper dans vos ressources String sont les suivants:

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

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

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

Cependant, pour être sûr, vous ne devez utiliser que <b>, <i> et <u> tels qu'ils sont répertoriés dans la documentation.

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

La seule différence est que, si vous souhaitez utiliser vos chaînes HTML à partir de Java code , vous devez utiliser getText(...) au lieu de getString(...). maintenant, comme le premier conserve le style et que le second va simplement l'enlever.

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

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

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

Modifier:

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

Voir le graphique suivant pour une comparaison:

enter image description here

124
caw

Échappez à vos balises HTML ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
15
ekawas

Dernière mise à jour:

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

Le code suivant prend en charge Android N et les versions 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));
}
10
Ranjith Kumar

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 permettant au développeur de spécifier cela dans le fichier XML.

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

Une fois que vous les avez définis, vous pouvez vous exprimer avec HTML en fichiers xml sans avoir à appeler de 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.

enter image description here

res/values ​​/ strings.xml (la ressource chaîne en 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();
    }
}
}
10
Steven Spungin
  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);
3
Dishant Kawatra

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 je reçois d'un serveur:

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

Cela semble être 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

2
Linh Lino