Legen Sie TextView-Text aus einer HTML-formatierten Zeichenfolgenressource in XML fest

195

Ich habe einige feste Saiten in mir strings.xml, so etwas wie:

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

und in meinem Layout habe ich eine, TextViewdie ich mit der HTML-formatierten Zeichenfolge füllen möchte.

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

Wenn ich das mache, ist der Inhalt von formattedtextnur der Inhalt von somestringHTML-Tags entfernt und somit unformatiert.

Ich weiß, dass es möglich ist, den formatierten Text programmgesteuert mit festzulegen

.setText(Html.fromHtml(somestring));

weil ich dies in anderen Teilen meines Programms verwende, in denen es wie erwartet funktioniert.

Um diese Funktion aufzurufen, benötige ich eine Activity, aber im Moment ist mein Layout nur eine einfache mehr oder weniger statische Ansicht in einfachem XML, und ich würde es vorziehen, dies so zu belassen, um mich vor dem Aufwand zu bewahren, eine Activitynur zum Festlegen einiger zu erstellen Text.

Übersehe ich etwas Offensichtliches? Ist das überhaupt nicht möglich? Hilfe oder Problemumgehungen sind willkommen!

Bearbeiten: Ich habe gerade einige Dinge ausprobiert und es scheint, dass die HTML-Formatierung in XML einige Einschränkungen hat:

  • Tags müssen in Kleinbuchstaben geschrieben werden

  • Einige Tags, die hier erwähnt werden, funktionieren nicht, z. B. <br/>(es ist möglich, \nstattdessen zu verwenden )

Slup
quelle
1
Ich weiß es schon lange, aber ich konnte <br> und nicht \ n für eine neue Zeile verwenden, indem ich den HTML-Code für eine Textansicht verwendete.
Tam
2
Kann das nur mit XML funktionieren? Ich habe eine kleine Prämie auf die Antwort. Ich würde an dieser Stelle, an der ich es bereits codiert habe, Nein als sachliche Antwort nehmen.
danny117
1
Ich finde es interessant, dass niemand die Frage tatsächlich beantwortet hat. Das OP gibt an, dass er weiß, wie es mit fromHtml () geht, möchte es aber direkt in der Layoutdatei machen (obwohl die Gründe nicht gut sind ... Sie haben immer eine Aktivität / einen Kontext zur Verfügung, wenn Sie darauf zurückgreifen der Bildschirm). Keine der Antworten befasst sich auch mit den Auswirkungen von Ankertags.
Lilbyrdie

Antworten:

481

Nur für den Fall, dass jemand dies findet, gibt es eine schönere Alternative, die nicht dokumentiert ist (ich bin nach stundenlanger Suche darüber gestolpert und habe sie schließlich in der Fehlerliste für das Android SDK selbst gefunden). Sie CAN raw HTML in strings.xml enthalten, so lange wie Sie es wickeln in

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

Beispiel:

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

Dann in Ihrem Code:

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

IMHO, das ist um mehrere Größenordnungen besser zu handhaben :-)

Bitbang3r
quelle
26
Nur um hinzuzufügen, können Sie auch Apostrophe / einfache Anführungszeichen innerhalb des CDATA-Blocks zurücksetzen, sodass Sie Dinge wie <b> can \ 't </ b> anstelle der unendlich hässlicheren <b> can & apos; t <haben können / b>
Bitbang3r
5
Funktioniert das noch Ich habe es gerade versucht und es zeigt buchstäblich die <p> und </ p> an.
Peri Hartman
1
@PeriHartman Hast du auch das Html.fromHtml(getString(R.string.nice_html))bisschen gemacht? :)
async
1
Woher kommt TextView foo = (TextView) findViewById (R.id.foo); foo.setText (Html.fromHtml (getString (R.string.nice_html))); muss gehen?
RustyIngles
2
Gibt es eine Möglichkeit, "Html.fromHtml" zu vermeiden?
Android-Entwickler
127

Da die beste Antwort hier darauf hindeutet, dass etwas nicht stimmt (oder zumindest zu kompliziert ist), sollte dies meiner Meinung nach aktualisiert werden, obwohl die Frage ziemlich alt ist:

Wenn Sie String-Ressourcen in Android verwenden, müssen Sie nur getString(...)Java-Code aufrufen oder android:text="@string/..."in Ihrem Layout-XML verwenden.

Auch wenn Sie HTML-Markup in Ihren Strings verwenden möchten, müssen Sie nicht viel ändern:

Die einzigen Zeichen, die Sie in Ihren String-Ressourcen maskieren müssen, sind:

  • doppeltes Anführungszeichen: "wird\"
  • einfaches Anführungszeichen: 'wird\'
  • kaufmännisches Und: &wird &#38;oder&amp;

Das heißt, Sie können Ihr HTML-Markup hinzufügen, ohne die Tags zu umgehen:

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

Allerdings sollten Sie nur verwenden <b>, <i>und <u>wie sie in der Dokumentation aufgeführt sind.

Wenn Sie Ihre HTML-Zeichenfolgen aus XML verwenden möchten, verwenden Sie sie einfach weiter. android:text="@string/..."Dies funktioniert einwandfrei.

Der einzige Unterschied besteht darin , dass, wenn Sie Ihre HTML - Strings verwenden möchten von Java - Code , müssen Sie verwenden getText(...)statt getString(...)jetzt, da erstere den Stil und die letzteren festhält , wird es gerade weg abzustreifen.

So einfach ist das. Keine CDATA, nein Html.fromHtml(...).

Sie werden nur brauchen, Html.fromHtml(...)wenn Sie haben in HTML - Markup kodieren Ihre Sonderzeichen. Verwenden Sie es mit getString(...)dann. Dies kann erforderlich sein, wenn Sie den String an übergeben möchten String.format(...).

Das ist alles beschrieben in den Dokumenten .

Bearbeiten:

Es gibt keinen Unterschied zwischen nicht getText(...)entkoppeltem HTML (wie ich vorgeschlagen habe) oder CDATAAbschnitten und Html.fromHtml(...).

Einen Vergleich finden Sie in der folgenden Grafik:

Geben Sie hier die Bildbeschreibung ein

krächzen
quelle
Meins zieht es aus. Ich benutze den folgenden Code:getResources().getText(R.string.codename)
Si8
3
Um besser zu helfen, müsste ich die Java / XML-Auszüge sehen. Aber wie ich schon geschrieben habe: Sie sind nur sicher , wenn Sie mit <b>, <i>, <u>. Andere Tags werden nicht immer unterstützt.
Caw
1
Ihre Antwort funktioniert und ist einfach. Fügen Sie einfach Ihren String mit den gewünschten HTML-Tags in die Datei strings.xml ein und verweisen Sie auf ihn aus Ihrer Layout-XML-Datei. Ich habe das <sup> -Tag verwendet.
Peri Hartman
1
Ihre ist eine andere Lösung, keine Alternative zur anderen, da sie nicht alle Tags unterstützt, wie es die andere tut. Ich sehe keinen Vorteil in dieser Lösung, wenn die andere sehr einfach ist.
mobilepotato7
1
Wie ich bei der Verwendung von "CDATA" erlebt habe, gibt es beispielsweise ein Problem: <! [CDATA [... HTML ...]]> mit 22 Buchstaben und einem HTML-Teil mit 10. Wenn Sie also HTML.fromhtml (verwenden) getstring (...)) Ihr Text wird korrekt angezeigt, der Textinhalt benötigt jedoch 22 Buchstaben. Ich habe in der Listenansicht verwendet und unkrautige Räume gesehen. gettext () ist also BESSER.
David
16

Entfliehen Sie Ihren HTML-Tags ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
ekawas
quelle
Das sagen die Dokumente: developer.android.com/intl/zh-TW/guide/topics/resources/… aber reicht das aus TextView, um HTML anzuzeigen?
Macarse
3
Ich habe dies getestet, und wenn Sie es aus dem Java-Quellcode verwenden, ist es in Ordnung. Wenn Sie Ihren Text jedoch direkt aus Layout-XML verknüpfen, werden die Tags in der
Textansicht angezeigt
Verwenden Sie speziell die Klasse [ developer.android.com/reference/android/text/Html.html] , um den Text in einer Ansicht anzuzeigen fromHTML().
Ekawas
@ZoltanF ist richtig, wenn Sie android: text = "" aus einem Layout mit HTML verwenden, werden die Tags in der Zeichenfolge angezeigt.
Andrew Mackenzie
1
Wenn Sie die HTML-Zeichenfolge direkt aus XML verwenden möchten, dürfen Sie keine HTML-Sonderzeichen in der Zeichenfolge codieren. Wenn Sie jedoch die Zeichenfolge Code verwenden möchten über Html.fromHTML()Sie müssen die speziellen Zeichen kodieren. Seltsam!
Caw
11

Android verfügt nicht über eine Spezifikation, die den Typ der Ressourcenzeichenfolge angibt (z. B. Text / Nur-Text oder Text / HTML). Es gibt jedoch eine Problemumgehung, mit der der Entwickler dies in der XML-Datei angeben kann.

  1. Definieren Sie ein benutzerdefiniertes Attribut, um anzugeben, dass das Attribut android: text HTML ist.
  2. Verwenden Sie eine untergeordnete Textansicht.

Sobald Sie diese definiert haben, können Sie sich mit HTML in XML-Dateien ausdrücken, ohne setText (Html.fromHtml (...)) erneut aufrufen zu müssen. Ich bin ziemlich überrascht, dass dieser Ansatz nicht Teil der API ist.

Diese Lösung funktioniert in dem Maße, in dem der Android Studio-Simulator den Text als gerenderten HTML-Code anzeigt.

Geben Sie hier die Bildbeschreibung ein

res / values ​​/ strings.xml (die String-Ressource als HTML)

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

layout.xml (nur die relevanten Teile)

Deklarieren Sie den benutzerdefinierten Attribut-Namespace und fügen Sie das Attribut android_ex: isHtml hinzu. Verwenden Sie auch die Unterklasse von 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 (benutzerdefinierte Attribute für die Unterklasse definieren)

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

TextViewEx.java (die Unterklasse von 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
quelle
Dieser Ansatz ist besser, wenn die App HTML-formatierte Zeichenfolgen an mehreren Stellen verwendet und HTML.fromHtml an jeder Stelle aufruft. Die App selbst hat zwei Ansichten, eine für normales und eine für HTML.
Manju
10

Neuestes Update:

Html.fromHtml(string);// veraltet nach Android N Versionen ..

Der folgende Code unterstützt Android N und höhere Versionen ...

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
quelle
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
quelle
2

Ich habe einen anderen Fall, in dem ich keine Chance habe, CDATA in die XML-Datei einzufügen, wenn ich die Zeichenfolge HTML von einem Server erhalte.

Folgendes bekomme ich von einem Server:

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

Es scheint komplizierter zu sein, aber die Lösung ist viel einfacher.

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

}

Ich hoffe es hilft!
Linh

Linh Lino
quelle
4
Wo ist die Implementierung der Funktion getHTMLContentFromAServer ()
Pallavi