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

У меня есть некоторые фиксированные строки внутри моего 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 только для установки некоторого текста.

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

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

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

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

Ответ 1

На всякий случай, если кто-нибудь найдет это, есть более приятная альтернатива, которая не документирована (я споткнулся о ней после поиска часов и, наконец, нашел ее в списке ошибок для самого Android SDK). Вы CAN включаете необработанный 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)));

IMHO, на несколько порядков лучше работать с: -)

Ответ 2

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

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

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

Единственными символами, которые вам нужно избежать в ваших ресурсах String, являются:

  • двойная кавычка: " становится \"
  • одинарная кавычка: ' становится \'
  • ampersand: & становится &#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(...), так как первые сохраняют стиль и последний просто отключит его.

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

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

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

Edit:

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

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

enter image description here

Ответ 3

Сбросьте свои HTML-теги...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>

Ответ 4

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

  • Определите настраиваемый атрибут, чтобы указать, что атрибут android: text является html.
  • Используйте подклассу 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();
    }
}
}

Ответ 5

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

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

Ответ 6

У меня есть другой случай, когда у меня нет возможности поместить 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());

}

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

Ответ 7

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