Установить текст TextView из строкового ресурса в формате html в XML

198

У меня внутри есть фиксированные строки strings.xml, например:

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

и в моем макете у меня есть, TextViewкоторый я хотел бы заполнить строкой в ​​формате html.

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

если я это сделаю, содержимое formattedtextбудет просто содержимым без somestringкаких-либо тегов html и, следовательно, неформатированным.

Я знаю, что можно программно установить форматированный текст с помощью

.setText(Html.fromHtml(somestring));

потому что я использую это в других частях моей программы, где он работает должным образом.

Для вызова этой функции мне нужен Activity, но на данный момент мой макет представляет собой простое более или менее статическое представление в простом XML, и я бы предпочел оставить его таким, чтобы избавить меня от накладных расходов на создание Activityпросто для установки некоторых текст.

Я не замечаю чего-то очевидного? Неужели это вообще невозможно? Любая помощь или обходные пути приветствуются!

Изменить: просто попробовал кое-что, и кажется, что форматирование HTML в xml имеет некоторые ограничения:

  • теги должны быть написаны в нижнем регистре

  • некоторые теги, упомянутые здесь , не работают, например <br/>( \nвместо них можно использовать )

шлепок
источник
1
Я уже давно знаю, но я смог использовать <br>, а не \ n для новой строки, используя html для TextView.
Tam
2
Может ли это работать только из xml? Я назначил небольшую награду за ответ. Я бы принял «нет» как фактический ответ, на данный момент я уже закодировал его.
danny117
2
Мне интересно, что на вопрос никто не ответил. OP заявляет, что он знает, как это сделать с fromHtml (), но хочет сделать это непосредственно в файле макета (хотя причины не веские ... у вас всегда есть действие / контекст, если вы рисуете на экран). Ни один из ответов также не затрагивает эффекты якорных тегов.
lilbyrdie

Ответы:

481

На случай, если кто-нибудь найдет это, есть более приятная альтернатива, которая не задокументирована (я споткнулся о ней после нескольких часов поиска и, наконец, нашел ее в списке ошибок для самого Android SDK). Вы МОЖЕТЕ включить необработанный HTML в strings.xml, если вы оберните его в

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

Пример:

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

Затем в вашем коде:

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

ИМХО, с этим работать на несколько порядков приятнее :-)

Bitbang3r
источник
26
Чтобы добавить, вы также можете экранировать апострофы / одинарные кавычки с обратной косой чертой внутри блока CDATA, чтобы вы могли иметь такие вещи, как <b> can \ 't </b> вместо бесконечно уродливого <b> can & apos; t < / b>
Bitbang3r 06
5
Это все еще работает? Я просто попробовал, и он буквально отображает <p> и </p>.
Пери Хартман
1
@PeriHartman Ты тоже Html.fromHtml(getString(R.string.nice_html))немного поработал ? :)
async
1
Где находится TextView foo = (TextView) findViewById (R.id.foo); foo.setText (Html.fromHtml (getString (R.string.nice_html))); должен идти?
RustyIngles 01
2
Есть ли способ избежать "Html.fromHtml"?
разработчик Android
130

Поскольку главный ответ здесь предполагает что-то неправильное (или, по крайней мере, слишком сложное), я считаю, что это следует обновить, хотя вопрос довольно старый:

При использовании ресурсов String в Android вам просто нужно вызвать getString(...)из кода Java или использовать android:text="@string/..."в макете XML.

Даже если вы хотите использовать разметку HTML в своих строках, вам не нужно сильно менять:

Единственные символы, которые вам нужно экранировать в ваших строковых ресурсах:

  • двойная кавычка: "становится\"
  • одинарная кавычка: 'становится\'
  • амперсанд: &становится &#38;или&amp;

Это означает, что вы можете добавить разметку HTML, не экранируя теги:

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

Однако, чтобы быть уверенным, вы должны использовать только <b>, <i>и <u>как они перечислены в документации.

Если вы хотите использовать свои HTML-строки из XML , просто продолжайте использовать android:text="@string/...", он будет работать нормально.

Единственное отличие состоит в том, что если вы хотите использовать свои HTML-строки из кода Java , вы должны использовать getText(...)вместо него getString(...)now, поскольку первый сохраняет стиль, а второй просто удаляет его.

Это так просто. Нет CDATA, нет Html.fromHtml(...).

Вам нужно будет только Html.fromHtml(...)если вы сделали закодировать свои специальные символы в HTML разметке. Используйте это с getString(...)then. Это может быть необходимо, если вы хотите передать String в String.format(...).

Все это тоже описано в документации .

Редактировать:

Нет никакой разницы между getText(...)неэкранированным HTML (как я предлагал) или CDATAразделами и Html.fromHtml(...).

См. Следующий рисунок для сравнения:

введите описание изображения здесь

каркать
источник
Мой снимает это. Я использую следующий код:getResources().getText(R.string.codename)
Si8
3
Чтобы помочь лучше, мне нужно увидеть отрывки из Java / XML. Но , как я уже писал: Вы только уверены , что если вы используете <b>, <i>, <u>. Другие теги не всегда поддерживаются.
caw
1
Ваш ответ работает и прост. Просто поместите свою строку в strings.xml с желаемыми тегами html и укажите на нее ссылку из XML-файла макета. Я использовал тег <sup>.
Пери Хартман
1
Ваше - другое решение, а не альтернатива другому, потому что оно поддерживает не все теги, как другие. Я не вижу никаких преимуществ в этом решении, когда другое очень простое.
mobilepotato7
1
Как я испытал при использовании "CDATA", возникла проблема, например: <! [CDATA [... HTML ...]]> с 22 буквами, а в html-части - 10. поэтому, если вы используете HTML.fromhtml ( getstring (...)) ваш текст будет отображаться правильно, но для его содержимого требуется пробел из 22 букв. Я использовал в списке и видел слабые места. так что gettext () ЛУЧШЕ.
David
16

Избегайте тегов HTML ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
экавас
источник
Это то, что говорят документы: developer.android.com/intl/zh-TW/guide/topics/resources/… но достаточно ли этого TextViewдля отображения HTML?
Macarse
3
Я тестировал это, и если вы используете его из исходного кода java, все в порядке. Но если вы связываете свой текст непосредственно из XML макета, теги отображаются в текстовом представлении (например, <B> Title </B> ...)
ZoltanF
Чтобы показать текст в представлении, используйте класс [ developer.android.com/reference/android/text/Html.html] , в частности fromHTML().
ekawas
@ZoltanF прав, использование android: text = "" из макета с HTML покажет теги в строке.
Эндрю Маккензи,
1
Если вы хотите использовать строку HTML непосредственно из XML, вы не можете кодировать специальные символы HTML в строке. Однако, если вы хотите использовать строку из кода через, Html.fromHTML()вам необходимо закодировать специальные символы. Странный!
caw
12

Android не имеет спецификации для указания типа строки ресурса (например, text / plain или text / html). Однако существует обходной путь, который позволит разработчику указать это в файле XML.

  1. Определите настраиваемый атрибут, чтобы указать, что атрибут android: text имеет значение html.
  2. Используйте подкласс TextView.

Как только вы их определите, вы сможете выражать себя с помощью HTML в файлах xml без повторного вызова setText (Html.fromHtml (...)). Я очень удивлен, что этот подход не является частью API.

Это решение работает в той степени, в которой симулятор студии Android будет отображать текст как визуализированный HTML.

введите описание изображения здесь

res / values ​​/ strings.xml (строковый ресурс как HTML)

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

layout.xml (только соответствующие части)

Объявите пространство имен настраиваемого атрибута и добавьте атрибут android_ex: isHtml. Также используйте подкласс 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 (определите настраиваемые атрибуты для подкласса)

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

TextViewEx.java (подкласс 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();
    }
}
}
Стивен Спунгин
источник
Этот подход будет лучше, если приложение использует строки в формате HTML в нескольких местах, а не вызывает HTML.fromHtml везде. Само приложение будет иметь два представления: одно для обычного, другое для HTML.
Манджу,
превосходно !! .. Спасибо за код.
Хусснайн Хашми,
10

Последнее обновление:

Html.fromHtml(string);// устарело после версий Android N.

Следующий код поддерживает версии Android N и выше ...

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));
}
Ранджит Кумар
источник
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);
Дишант Каватра
источник
2

У меня есть другой случай, когда у меня нет возможности поместить CDATA в xml, поскольку я получаю строку HTML с сервера.

Вот что я получаю от сервера:

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

Вроде бы сложнее, но решение намного проще.

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

}

Надеюсь, это поможет!
Линь

Линь Лино
источник
4
где реализация функции getHTMLContentFromAServer ()
Паллави