Як відобразити HTML у TextView?


756

У мене простий HTML :

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

Я хочу відобразити текст у стилі HTML TextView. Як це зробити?


7
Ви хочете відобразити теги чи пропустити їх?
DerMike

1
ознайомтесь із цим посиланням на робочий приклад javatechig.com/2013/04/07/how-to-display-html-in-android-view
Nilanchal

1
Якщо ви шукаєте рішення застарілої, вона просто тут stackoverflow.com/questions/37904739 / ...
crgarridos

Відповіді:


1350

Вам потрібно скористатися Html.fromHtml()для використання HTML у ваших рядках XML. Просто посилання рядка з HTML у вашому XML-макеті не буде працювати.

Ось що ви повинні зробити:

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

7
h2за визначенням створює навколо себе багато запасів. а pтакож має деякий запас. якщо ви не хочете розриву, ви можете розглянути можливість використання інших html-елементів.
Девід Хедлунд

10
Костадин, ви можете помістити теги в XML, їх просто потрібно загорнути в дужки CDATA.
Джерард

3
Для тих, хто хоче, щоб він працював з тегами ol / ul / li, перегляньте це рішення: stackoverflow.com/a/3150456/1369016
Tiago,

13
Так і має бути android.text.Html.fromHtml. Я знаю, що більшість IDE виправлять це за вас, але для читабельності приємніше знати назви пакетів.
Мартін

14
@Martin Я б не сказав за читабельність, а скоріше за вичерпність . Повністю кваліфіковані імена IMO, що використовуються безпосередньо в такому коді, менш читаються, ніж короткі імена. Але я погоджуюсь з вами щодо того, що така відповідь повинна містити пакет (зі зворотною запискою), який є посиланням тут;)
Джоффрі,

76

SetText (Html.fromHtml (bodyData)) є застарілим після апі 24. Тепер ви повинні зробити це:

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

4
Чому використовується API FHT_HTML_MODE_LEGACY в API 24+?
galcyurio

64

Погляньте на це: https://stackoverflow.com/a/8558249/450148

Це дуже добре теж !!

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

Він працює лише для декількох тегів.


12
Чи є список тегів, які підтримуються цим методом?
менте

23
@mente Відповідно до вихідних кодів : <a>, <b>, <big>, <blockquote>, <br>, <cite>, <dfn> <div align = "...">, <em>, < font size = "..." color = "..." face = "..."> <h1-6>, <i>, <img src = "...">, <p>, <small > <strike>, <strong>, <sub>, <sup>, <tt>, <u> (джерело: dzone.com/snippets/how-display-html-android )
JerabekJakub

@JerabekJakub, але будьте обережні, якщо ви збираєтеся обробляти img, вам доведеться реалізувати Html.ImageGetter.
MiguelHincapieC

@ 0mahc0, коли можна реалізувати img, чи можна встановити розмір?
Джон

1
@Joh так можливо. Коли ви реалізуєте .ImageGetter, існує метод, який називається getDravable (String source). Якщо вам потрібна додаткова допомога, створіть питання та позначте мене, я наведу вам приклад;)
MiguelHincapieC

41

Якщо ви хочете мати можливість налаштувати його через xml без будь-яких змін у коді Java, ви можете вважати цю ідею корисною. Просто ви викликаєте init від конструктора і встановлюєте текст як 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"/>

1
Що таке "...".
Проясніть,

25

Якщо ви намагаєтеся показати HTML з ідентифікатора рядкового ресурсу, форматування може не відображатися на екрані. Якщо це відбувається з вами, спробуйте використовувати замість тегів 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));

Детальнішу інформацію див. У цій публікації .


Дякую, це зробили для мене, використовуючи API 23.
XMAN

24

Наведений нижче код дав найкращий результат для мене.

TextView myTextview = (TextView) findViewById(R.id.my_text_view);
htmltext = <your html (markup) character>;
Spanned sp = Html.fromHtml(htmltext);
myTextview.setText(sp);

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

як ви змінюєте колір якоря?
EdmundYeung99

android: textColorLink = "color"
Педро

це забарвить увесь перегляд тексту в червоний колір, але якщо я хочу лише теги прив’язки, мені потрібно обгорнути тег <a> тегами <font> і додати там колір
EdmundYeung99

11

Якщо ви просто хочете відобразити текст у форматі html та не дуже потрібен TextView, тоді візьміть a WebViewта скористайтеся ним, як описано нижче:

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

Це також не обмежує вас декількома тегами HTML.


2
Незважаючи на те , що це дуже корисний спосіб обійти заборонений набір HTML - теги, підтримувані TextView, має той недолік , що він НЕ дуже добре працювати з layout_height="wrap_content". Натомість доведеться встановити явну висоту або match_parent.
Ridcully

3
веб-перегляд дуже повільний
Jackky777

11

Найкращий підхід до використання розділів CData для рядка у файлі strings.xml для отримання фактичного відображення вмісту HTML у TextView, наведений нижче фрагмент коду дасть вам ідеальну ідею.

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

Розділ CData в рядковому тексті зберігає дані тегів html недоторканими навіть після форматування тексту методом String.format. Отже, Html.fromHtml (str) прекрасно працює, і ви побачите жирний текст у вітальному повідомленні.

Вихід:

Ласкаво просимо до вашого улюбленого магазину музичних програм. Увійшли як: ім’я користувача


Дякую, це зробили для мене, використовуючи API 23.
XMAN

спасибі, ти врятував мій день :) Просто невелике доповнення: нам потрібно додати цей чек до вищевказаного коду: якщо (Build.VERSION.SDK_INT> = Build.VERSION_CODES.N) {// для 24 api та більше textView.setText ( Html.fromHtml (welcomeStr, Html.FROM_HTML_OPTION_USE_CSS_COLORS)); } else {// або для старих api textView.setText (Html.fromHtml (welcomeStr)); }. Значення для прапора 2-го параметра для API> = 24 може бути будь-яким відповідно до вимоги.
AndroidGuy


6

Я також хочу запропонувати наступний проект: https://github.com/NightWhistler/HtmlSpanner

Використання майже таке ж, як і конвертер для Android за замовчуванням:

(new HtmlSpanner()).fromHtml()

Виявив це після того, як я вже запустив власну реалізацію html до перехідного перетворювача, тому що стандартний Html.fromHtml не забезпечує достатньої гнучкості в управлінні візуалізацією і навіть не має можливості використовувати спеціальні шрифти з ttf


Я отримую таку помилку: Помилка: (80, 13) Не вдалося вирішити: com.osbcp.cssparser: cssparser: 1.5 Як вирішити цю проблему?
Араджу

6

Я знаю, це питання давнє. Інші відповіді тут пропонують Html.fromHtml()метод. Я пропоную вам використовувати HtmlCompat.fromHtml()з androidx.core.text.HtmlCompatпакета. Оскільки це назад сумісна версія Htmlкласу.

Приклад коду:

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

Таким чином ви можете уникнути перевірки версії API Android, і це просто у використанні (однолінійне рішення).


Чим це відрізняється від старої метхоти? Яке призначення режиму html?
користувач1209216

1
Шукав щось подібне. Спасибі :)
Subhrajyoti Sen

5

Просте використання Html.fromHtml("html string"). Це спрацює. Якщо в рядку є теги на зразок, <h1>тоді прийдуть пробіли. Але ми не можемо усунути ці простори. Якщо ви все-таки хочете видалити пробіли, ви можете видалити теги в рядку, а потім передати рядок методу Html.fromHtml("html string");. Загалом ці рядки надходять із сервера (динамічно), але не часто, якщо це краще, щоб передавати рядок як до методу, ніж намагатися видалити теги з рядка.



4

Складіть глобальний метод на зразок:

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

Ви також можете використовувати його у своїй діяльності / фрагменті, як:

text_view.setText(stripHtml(htmlText));

3

Я реалізував це за допомогою веб-перегляду. У моєму випадку мені потрібно завантажити зображення з URL-адреси разом з текстом у текстовому режимі, і це працює для мене.

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

Для правильного відображення UTF-8 вам потрібно встановити тип MIME на "text / html; charset = UTF-8".
shawkinaw

3

За допомогою різних відповідей пропонувалося використовувати рамковий клас Html, як запропоновано тут, але, на жаль, цей клас відрізняється поведінкою в різних версіях Android та різних неадресованих помилок, як це продемонстровано у випусках 214637 , 14778 , 235128 та 75953 .

Тому ви можете використовувати бібліотеку сумісності для стандартизації та підтримки класу Html для версій Android, що включає більше зворотних зворотів для елементів та стилів:

Проект Github HtmlCompat

Незважаючи на те, що він схожий на клас Html рамки, деякі зміни підпису були потрібні, щоб дозволити більше зворотних зворотів. Ось зразок зі сторінки 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);

@MartijnPieters Раніше закрита відповідь була дублікатом відповіді на це питання стосовно депресії рамкового методу . Я розширив причину використання кращого підходу із використанням бібліотеки сумісності. Я не думаю, що будь-яке питання доцільно позначати як дублікати один одного, оскільки вони явно відрізняються.
Пол Ламмерцма

2

Щоразу, коли ви пишете спеціальний перегляд тексту, основна функція набору тексту HTML буде зникала з деяких пристроїв.

Тому нам потрібно зробити наступні додаткові кроки - це робота

public class CustomTextView extends TextView {

    public CustomTextView(..) {
        // other instructions
        setText(Html.fromHtml(getText().toString()));
    }
}

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

оновлення відповіді вище


1

Використовуйте код нижче, щоб отримати рішення:

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

Метод утітліті

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

1

Створено розширення Kotlin для перетворення HTML з String -

fun String?.toHtml(): Spanned? {
    if (this.isNullOrEmpty()) return null
    return HtmlCompat.fromHtml(this, HtmlCompat.FROM_HTML_MODE_COMPACT)
}

0

Можна запропонувати дещо хитре, але все ж геніальне рішення! Я отримав ідею з цієї статті та адаптував її для Android. В основному ви використовуєте a WebViewі вставляєте HTML, який хочете показати та відредагувати, у редагований тег div. Таким чином, коли користувач натискає WebViewклавіатуру, з'являється і дозволяє редагувати. Вони просто додають JavaScript, щоб повернути відредагований HTML і вуаля!

Ось код:

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

І ось компонент як Гіст.

Примітка: мені не знадобився зворотний виклик зміни висоти від оригінального рішення, тому його тут немає, але ви можете легко додати його, якщо потрібно.


0

Якщо ви використовуєте androidx.* класи у своєму проекті, ви повинні використовувати HtmlCompat.fromHtml(text, flag). Джерело методу:

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

Це кращий спосіб, ніж Html.fromHtml, оскільки код менше, лише один рядок, і рекомендований спосіб його використання.


0

Ви можете використовувати просту функцію розширення Kotlin таким:

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

І використання:

textViewMessage.setHtmlText("Message: <b>Hello World</b>")

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.