Ustaw tekst TextView z zasobu łańcucha sformatowanego w formacie HTML w XML

195

Mam kilka stałych ciągów w sobie strings.xml, coś w stylu:

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

a w moim układzie mam taki, TextViewktóry chciałbym wypełnić ciągiem sformatowanym w formacie HTML.

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

jeśli to zrobię, zawartość formattedtextjest po prostu somestringpozbawiona tagów HTML i dlatego jest niesformatowana.

Wiem, że możliwe jest programowe ustawienie sformatowanego tekstu

.setText(Html.fromHtml(somestring));

ponieważ używam tego w innych częściach mojego programu, gdzie działa zgodnie z oczekiwaniami.

Aby wywołać tę funkcję muszę mieć Activity, ale w tej chwili mój układ jest tylko prosty bardziej lub mniej statyczny widok w prostym formacie XML i wolałbym zostawić to w ten sposób, aby zapisać mnie od napowietrznej stworzenie Activitypo prostu ustawić niektóre tekst.

Czy przeoczam coś oczywistego? Czy to w ogóle nie jest możliwe? Każda pomoc lub obejścia są mile widziane!

Edycja: Właśnie wypróbowałem kilka rzeczy i wydaje się, że formatowanie HTML w xml ma pewne ograniczenia:

  • tagi muszą być zapisane małymi literami

  • niektóre wymienione tu tagi nie działają, np. <br/>(można \nzamiast tego użyć )

slup
źródło
1
Już dawno wiem, ale mogłem używać <br>, a nie \ n dla nowej linii przy użyciu HTML dla TextView.
Tam
2
Czy to może działać tylko z XML? Mam małą nagrodę za odpowiedź. Nie przyjąłbym żadnej odpowiedzi faktycznej w tym miejscu, w którym już ją kodowałem.
danny117
1
Uważam za interesujące, że nikt tak naprawdę nie odpowiedział na pytanie. OP twierdzi, że wie, jak to zrobić za pomocą fromHtml (), ale chce to zrobić bezpośrednio w pliku układu (chociaż powody nie są dobre ... zawsze masz dostęp do działania / kontekstu, jeśli korzystasz z ekran). Żadna z odpowiedzi nie dotyczy również efektów tagów zakotwiczenia.
lilbyrdie,

Odpowiedzi:

481

Na wypadek, gdyby ktoś to znalazł, istnieje fajniejsza alternatywa, która nie została udokumentowana (potknąłem się o nią po wielu godzinach, aż w końcu znalazłem ją na liście błędów dla samego zestawu SDK systemu Android). Ci MOŻE zawierać surowego HTML w strings.xml, tak długo, jak owinąć go w

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

Przykład:

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

Następnie w kodzie:

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

IMHO, jest o kilka rzędów wielkości ładniejsza do pracy :-)

Bitbang3r
źródło
26
Aby dodać, możesz także apostrofy / pojedyncze cudzysłowy w odwrotnym ukośniku wewnątrz bloku CDATA, dzięki czemu możesz mieć takie rzeczy jak <b> can \ 't </b> zamiast nieskończenie brzydszego <b> can & tos < / b>
Bitbang3r,
5
Czy to nadal działa? Właśnie go wypróbowałem i dosłownie wyświetla <p> i </p>.
Peri Hartman,
1
@PeriHartman Czy ty też zrobiłeś Html.fromHtml(getString(R.string.nice_html))trochę? :)
async
1
Gdzie TextView foo = (TextView) findViewById (R.id.foo); foo.setText (Html.fromHtml (getString (R.string.nice_html))); muszę iść?
RustyIngles
2
Czy istnieje sposób na uniknięcie „Html.fromHtml”?
programista Androida
127

Ponieważ najważniejsza odpowiedź tutaj sugeruje coś złego (lub przynajmniej zbyt skomplikowanego), uważam, że należy to zaktualizować, chociaż pytanie jest dość stare:

Korzystając z zasobów String w Androidzie, wystarczy zadzwonić getString(...)z kodu Java lub użyć android:text="@string/..."w układzie XML.

Nawet jeśli chcesz używać znaczników HTML w swoich ciągach, nie musisz dużo zmieniać:

Jedynymi postaciami, które musisz uciec w zasobach String, są:

  • podwójny cudzysłów: "staje się\"
  • pojedynczy cudzysłów: 'staje się\'
  • ampersand: &staje się &#38;lub&amp;

Oznacza to, że możesz dodać znaczniki HTML bez uciekania się od tagów:

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

Jednak, aby mieć pewność, należy użyć tylko <b>, <i>i <u>jak są one wymienione w dokumentacji.

Jeśli chcesz używać ciągów HTML z XML , po prostu używaj dalej android:text="@string/...", będzie działać dobrze.

Jedyna różnica polega na tym, że jeśli chcesz używać ciągów HTML z kodu Java , musisz użyć getText(...)zamiast tego getString(...), ponieważ ten pierwszy zachowuje styl, a drugi po prostu go rozebra.

To takie proste. Bez CDATA, nie Html.fromHtml(...).

Konieczne będzie tylko Html.fromHtml(...)jeśli nie zakodowanie znaków specjalnych znaczników HTML. Użyj go getString(...)wtedy. Może to być konieczne, jeśli chcesz przekazać ciąg String.format(...).

Wszystko to opisano również w dokumentach .

Edytować:

Nie ma różnicy między getText(...)nieskalowanym HTML (jak zaproponowałem) lub CDATAsekcjami i Html.fromHtml(...).

Dla porównania zobacz następującą grafikę:

wprowadź opis zdjęcia tutaj

krakanie
źródło
Mój go rozbiera. Korzystam z następującego kodu:getResources().getText(R.string.codename)
Si8
3
Aby pomóc lepiej, musiałbym zobaczyć fragmenty Java / XML. Ale jak pisałem: Jesteś tylko pewien, czy używasz <b>, <i>, <u>. Inne tagi nie zawsze są obsługiwane.
caw
1
Twoja odpowiedź działa i jest prosta. Po prostu umieść swój ciąg w strings.xml z pożądanymi znacznikami html i odwołaj się do niego z pliku xml układu. Użyłem tagu <sup>.
Peri Hartman
1
Twoje jest innym rozwiązaniem, a nie alternatywą dla drugiego, ponieważ nie obsługuje wszystkich tagów, podobnie jak inne. Nie widzę żadnej przewagi w tym rozwiązaniu, gdy drugie jest bardzo proste.
mobilepotato7
1
Jak doświadczyłem używania „CDATA” mam problem, coś takiego jak na przykład: <! [CDATA [... HTML ...]]>, które mają 22 litery, a część HTML ma 10. więc jeśli używasz HTML.fromhtml ( getstring (...)) Twój tekst będzie wyświetlany poprawnie, ale jego treść wymaga 22 liter. Użyłem w widoku listy i widziałem zarośnięte przestrzenie. więc gettext () jest LEPSZY.
David
16

Unikaj tagów HTML ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
ekawas
źródło
Tak mówią doktorzy: developer.android.com/intl/zh-TW/guide/topics/resources/…, ale czy to wystarczy, TextViewaby wyświetlić HTML?
Macarse
3
Przetestowałem to i jeśli używasz go z kodu źródłowego Java, jest w porządku. Ale jeśli skojarzysz swój tekst bezpośrednio z układu XML, tagi zostaną wyświetlone w widoku tekstowym (np. <B> Tytuł </B> ...)
ZoltanF
Aby wyświetlić tekst w widoku, należy użyć klasy [ developer.android.com/reference/android/text/Html.html] , a konkretnie fromHTML().
ekawas
@ZoltanF ma rację, używając Androida: text = "" z układu z HTML pokaże tagi w ciągu.
Andrew Mackenzie
1
Jeśli chcesz użyć ciąg HTML bezpośrednio z XML, możesz nie kodują HTML specjalnych znaków w ciągu. Jeśli jednak chcesz użyć ciągu z kodu za pośrednictwem Html.fromHTML(), musisz zakodować znaki specjalne. Dziwne!
caw
11

Android nie ma specyfikacji wskazującej typ ciągu zasobów (np. Tekst / zwykły lub tekst / HTML). Istnieje jednak obejście, które pozwoli programiście określić to w pliku XML.

  1. Zdefiniuj niestandardowy atrybut, aby określić, że atrybut android: text to html.
  2. Użyj podklasy TextView.

Po ich zdefiniowaniu możesz wyrazić siebie za pomocą HTML w plikach xml bez konieczności ponownego wywoływania setText (Html.fromHtml (...)). Jestem raczej zaskoczony, że takie podejście nie jest częścią API.

To rozwiązanie działa w takim stopniu, że symulator studia Androida wyświetli tekst jako renderowany HTML.

wprowadź opis zdjęcia tutaj

res / wartości / strings.xml (zasób łańcucha jako HTML)

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

layout.xml (tylko odpowiednie części)

Zadeklaruj przestrzeń nazw niestandardowych atrybutów i dodaj atrybut android_ex: isHtml. Użyj także podklasy 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 / wartości / attrs.xml (zdefiniuj niestandardowe atrybuty dla podklasy)

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

TextViewEx.java (podklasa 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
źródło
Takie podejście będzie lepsze, jeśli aplikacja używa sformatowanych ciągów HTML w wielu miejscach, zamiast wywoływania HTML.fromHtml w każdym miejscu. Sama aplikacja będzie miała dwa widoki: jeden normalny, a drugi HTML.
Manju
10

Najnowsza aktualizacja:

Html.fromHtml(string);// przestarzałe po wersjach Androida N.

Poniższy kod obsługuje Androida N i nowsze wersje ...

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
źródło
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
źródło
2

Mam inny przypadek, gdy nie mam szansy na umieszczenie CDATA w xml, gdy otrzymuję ciąg HTML z serwera.

Oto, co otrzymuję z serwera:

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

Wydaje się to bardziej skomplikowane, ale rozwiązanie jest znacznie prostsze.

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

}

Mam nadzieję, że to pomoże!
Linh

Linh Lino
źródło
4
gdzie jest implementacja funkcji getHTMLContentFromAServer ()
Pallavi