Jak wyświetlić HTML w TextView?

756

Mam prosty HTML :

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

Chcę wyświetlić tekst w stylu HTML TextView. Jak to zrobić?

UMAR
źródło
7
Czy chcesz wyświetlić tagi, czy je pominąć?
DerMike,
1
sprawdź ten link dla działającego przykładu javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal
1
Jeśli szukasz rozwiązania przestarzałego, właśnie tutaj stackoverflow.com/questions/37904739/…
crgarridos

Odpowiedzi:

1350

Musisz użyć, Html.fromHtml()aby użyć HTML w ciągach XML. Po prostu odwołanie się do ciągu za pomocą HTML w układzie XML nie będzie działać.

Oto co powinieneś zrobić:

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
źródło
7
h2z definicji tworzy wokół siebie duży margines. a ptakże ma pewien margines. jeśli nie chcesz odstępu, możesz rozważyć użycie innych elementów HTML.
David Hedlund
10
Kostadin, możesz wstawiać tagi w XML, wystarczy owinąć je w nawiasy CDATA.
Gerard
3
Dla tych, którzy chcą, aby działał z tagami ol / ul / li, sprawdź to rozwiązanie: stackoverflow.com/a/3150456/1369016
Tiago
13
Tak powinno być android.text.Html.fromHtml. Wiem, że większość IDE naprawi to dla ciebie, ale dla czytelności lepiej poznać nazwy pakietów.
Martin
14
@Martin Nie powiedziałbym ze względu na czytelność, ale ze względu na kompletność . W pełni kwalifikowane nazwy IMO używane bezpośrednio w kodzie, takie jak ten, są mniej czytelne niż krótkie nazwy. Ale zgadzam się z tobą, że taka odpowiedź powinna dostarczyć paczkę (na marginesie), co stanowi punkt linku tutaj;)
Joffrey
76

setText (Html.fromHtml (bodyData)) jest przestarzały po API 24. Teraz musisz to zrobić:

 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
źródło
4
Dlaczego używa FROM_HTML_MODE_LEGACY w API 24+?
galcyurio
64

Spójrz na to: https://stackoverflow.com/a/8558249/450148

To też jest całkiem dobre !!

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

Działa tylko z kilkoma tagami.

Felipe Micaroni Lalli
źródło
12
Czy istnieje lista tagów obsługiwanych przez tę metodę?
mente
23
@mente Według kodów źródłowych : <a>, <b>, <big>, <blockquote>, <br>, <cite>, <dfn> <div align = "...">, <em>, < rozmiar czcionki = "..." color = "..." face = "..."> <h1-6>, <i>, <img src = "...">, <p>, <small > <strike>, <strong>, <sub>, <sup>, <tt>, <u> (źródło: dzone.com/snippets/how-display-html-android )
JerabekJakub
@JerabekJakub, ale uważaj, jeśli zamierzasz obsługiwać img, musisz zaimplementować Html.ImageGetter.
MiguelHincapieC
@ 0mahc0 kiedy ktoś implementuje img, czy można ustawić rozmiar?
Joh
1
@Joh tak, to możliwe. Podczas wdrażania .ImageGetter istnieje metoda o nazwie getDrawable (źródło String). Jeśli potrzebujesz dodatkowej pomocy, stwórz pytanie i oznacz mnie tagiem, dam ci przykład;)
MiguelHincapieC
41

Jeśli chcesz mieć możliwość skonfigurowania go za pomocą xml bez żadnych modyfikacji w kodzie Java, ten pomysł może okazać się pomocny. Wystarczy wywołać init z konstruktora i ustawić tekst jako 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
źródło
1
Co to jest „...”. Proszę o wyjaśnienie
Gilberta
25

Jeśli próbujesz wyświetlić HTML z identyfikatora zasobu ciąg, formatowanie może nie zostać wyświetlone na ekranie. Jeśli tak się dzieje, spróbuj zamiast tego użyć tagów 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));

Zobacz ten post, aby uzyskać więcej informacji.

Phileo99
źródło
Dzięki, zrobiłem to dla mnie - używając API 23.
XMAN
24

Poniższy kod dał mi najlepszy wynik.

TextView myTextview = (TextView) findViewById(R.id.my_text_view);
htmltext = <your html (markup) character>;
Spanned sp = Html.fromHtml(htmltext);
myTextview.setText(sp);
Rajiv Manivannan
źródło
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
źródło
jak zmienić kolor kotwicy?
EdmundYeung99
android: textColorLink = "color"
Pedro
spowoduje to pokolorowanie całego widoku tekstu na czerwony, ale jeśli chcę tylko tagów zakotwiczenia, muszę owinąć tag <a> tagami <font> i dodać tam kolor
EdmundYeung99
11

Jeśli chcesz tylko wyświetlić tekst HTML i naprawdę nie potrzebujesz go TextView, to weź WebViewi użyj go w następujący sposób:

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

Nie ogranicza to również kilku tagów HTML.

prom85
źródło
2
Chociaż jest to bardzo skuteczny sposób, aby ominąć ten ograniczony zestaw znaczników HTML, obsługiwanego przez TextView, ma tę wadę, że nie działa dobrze z layout_height="wrap_content". Zamiast tego będziesz musiał ustawić jawną wysokość lub match_parent.
Ridcully,
3
webview jest bardzo wolny
Jackky777
11

Najlepsze podejście do korzystania z sekcji CData dla łańcucha w pliku strings.xml w celu uzyskania rzeczywistego wyświetlania zawartości HTML w TextView poniższy fragment kodu da ci dobry pomysł.

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

Sekcja CData w tekście ciągłym zachowuje nietknięte dane znacznika html nawet po sformatowaniu tekstu za pomocą metody String.format. Html.fromHtml (str) działa dobrze i zobaczysz pogrubiony tekst w wiadomości powitalnej.

Wynik:

Witamy w ulubionym sklepie z aplikacjami muzycznymi. Zalogowany jako: nazwa użytkownika

Rajendhiran Easu
źródło
Dzięki, zrobiłem to dla mnie - używając API 23.
XMAN
dzięki, uratowałeś mi dzień :) Mały dodatek: Musimy dodać tę opcję do powyższego kodu: if (Build.VERSION.SDK_INT> = Build.VERSION_CODES.N) {// dla 24 api i więcej textView.setText ( Html.fromHtml (welcomStr, Html.FROM_HTML_OPTION_USE_CSS_COLORS)); } else {// lub dla starszych api textView.setText (Html.fromHtml (welcomStr)); }. Wartość flagi drugiego parametru dla API> = 24 może być dowolna zgodnie z wymaganiami.
AndroidGuy,
6

Chciałbym również zasugerować następujący projekt: https://github.com/NightWhistler/HtmlSpanner

Użycie jest prawie takie samo jak domyślny konwerter Androida:

(new HtmlSpanner()).fromHtml()

Znalazłem go po tym, jak już rozpocząłem od własnej implementacji html do spanowalnego konwertera, ponieważ standardowy Html.fromHtml nie zapewnia wystarczającej elastyczności w zakresie kontroli renderowania, a nawet nie ma możliwości używania niestandardowych czcionek z ttf

Fedotchenco Denis
źródło
Pojawia się następujący błąd: Błąd: (80, 13) Nie udało się rozwiązać: com.osbcp.cssparser: cssparser: 1.5 Jak to rozwiązać?
Araju,
6

Wiem, że to pytanie jest stare. Inne odpowiedzi tutaj sugerują Html.fromHtml()metodę. Proponuję użyć HtmlCompat.fromHtml()z androidx.core.text.HtmlCompatpakietu. Ponieważ jest to wersja Htmlklasy kompatybilna wstecz .

Przykładowy kod:

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

W ten sposób można uniknąć sprawdzania wersji interfejsu API Androida i jest on łatwy w użyciu (rozwiązanie jednoliniowe).

Shashanth
źródło
Czym to się różni od starego methota? Do czego służy tryb HTML?
user1209216
1
Szukałem czegoś takiego. Dzięki :)
Subhrajyoti Sen
5

Proste zastosowanie Html.fromHtml("html string"). To zadziała. Jeśli ciąg ma tagi, <h1>to będą spacje. Ale nie możemy wyeliminować tych przestrzeni. Jeśli nadal chcesz usunąć spacje, możesz usunąć tagi w ciągu, a następnie przekazać ciąg do metody Html.fromHtml("html string");. Również ogólnie te ciągi pochodzą z serwera (dynamiczne), ale nie często, jeśli lepiej jest przekazać ciąg tak, jak jest w metodzie, niż próbować usunąć tagi z ciągu.

brak
źródło
4
String value = html value ....
mTextView.setText(Html.fromHtml(value),TextView.BufferType.SPANNABLE)
gildas samuel
źródło
4

Stwórz globalną metodę, taką jak:

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

Możesz również użyć go w swojej aktywności / fragmencie, takich jak:

text_view.setText(stripHtml(htmlText));
Shylendra Madda
źródło
3

Zaimplementowałem to za pomocą widoku internetowego. W moim przypadku muszę załadować obraz z adresu URL wraz z tekstem w widoku tekstowym i to działa dla mnie.

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);
Zabójca
źródło
Aby poprawnie wyświetlić UTF-8, musisz ustawić typ MIME na „text / html; charset = UTF-8”.
shawkinaw
3

Sugerowano przez różne odpowiedzi używać HTML klasę ramową jak sugeruje tutaj, ale niestety ta klasa ma różne zachowanie w różnych wersjach Androida i różnych bezadresowych błędów, jak wykazano w sprawach 214637 , 14778 , 235128 i 75953 .

Dlatego możesz użyć biblioteki kompatybilności do standaryzacji i wykonania kopii zapasowej klasy HTML w różnych wersjach Androida, która zawiera więcej wywołań zwrotnych elementów i stylów:

Projekt Github HtmlCompat

Chociaż jest podobny do klasy Html frameworka, konieczne były pewne zmiany sygnatur, aby umożliwić więcej wywołań zwrotnych. Oto przykład ze strony 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
źródło
@MartijnPieters Poprzednio zamknięta odpowiedź była duplikatem odpowiedzi na to pytanie w związku z wycofaniem metody ramowej . Rozszerzyłem powód, dla którego lepszym rozwiązaniem byłoby użycie biblioteki kompatybilności. Nie sądzę, aby rozsądne było oznaczanie jednego z tych pytań jako duplikatów, ponieważ są one wyraźnie różne.
Paul Lammertsma
2

Za każdym razem, gdy piszesz niestandardowy widok tekstu, podstawowa funkcja ustawiania tekstu HTML zniknie z niektórych urządzeń.

Musimy więc wykonać następujące dodatkowe kroki, aby to działało

public class CustomTextView extends TextView {

    public CustomTextView(..) {
        // other instructions
        setText(Html.fromHtml(getText().toString()));
    }
}
Vinayak
źródło
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()));
    }
 }
}

aktualizacja odpowiedzi powyżej

Isaac Sekamatte
źródło
1

Użyj poniższego kodu, aby uzyskać rozwiązanie:

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

Metoda użyteczna

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

Utworzono rozszerzenia Kotlin do konwersji HTML z String -

fun String?.toHtml(): Spanned? {
    if (this.isNullOrEmpty()) return null
    return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT)
}
rzymski
źródło
0

Pozwól, że zasugeruję nieco pospieszne, ale genialne rozwiązanie! Pomysł zaczerpnąłem z tego artykułu i dostosowałem go do systemu Android. Zasadniczo używasz WebViewi wstawiasz HTML, który chcesz pokazać i edytować w edytowalnym znaczniku div. W ten sposób, gdy użytkownik stuknie, WebViewpojawi się klawiatura i umożliwia edycję. Po prostu dodajesz JavaScript, aby odzyskać edytowany kod HTML i voila!

Oto kod:

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

I tutaj jest element jako Gist.

Uwaga: Nie potrzebowałem wywołania zwrotnego zmiany wysokości w stosunku do oryginalnego rozwiązania, więc tutaj go brakuje, ale w razie potrzeby można go łatwo dodać.

AX
źródło
0

Jeśli używasz androidx.* klas w swoim projekcie, powinieneś użyć HtmlCompat.fromHtml(text, flag). Źródło metody to:

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

Jest to lepszy sposób niż Html.fromHtml, ponieważ jest mniej kodu, tylko jedna linia i zalecany sposób jego użycia.

Miś panda
źródło
0

Możesz użyć prostej funkcji rozszerzenia Kotlin w następujący sposób:

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

I użycie:

textViewMessage.setHtmlText("Message: <b>Hello World</b>")
seyfullah.bilgin
źródło
0

Po prostu użyj:

String variable="StackOverflow";
textView.setText(Html.fromHtml("<b>Hello : </b>"+ variable));
Sumit Shukla
źródło