Establecer texto TextView desde un recurso de cadena con formato html en XML

195

Tengo algunas cadenas fijas dentro de mi strings.xml, algo así como:

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

y en mi diseño tengo uno TextViewque me gustaría llenar con la cadena con formato html.

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

si hago esto, el contenido de formattedtextes solo el contenido somestringdespojado de cualquier etiqueta html y, por lo tanto, sin formato.

Sé que es posible configurar el texto formateado mediante programación con

.setText(Html.fromHtml(somestring));

porque lo uso en otras partes de mi programa donde funciona como se esperaba.

Para llamar a esta función, necesito una Activity, pero en este momento mi diseño es simplemente una vista más o menos estática en XML simple y prefiero dejarlo así, para salvarme de la sobrecarga de crear un Activitysolo para establecer algunos texto.

¿Estoy pasando por alto algo obvio? ¿No es posible en absoluto? Cualquier ayuda o soluciones son bienvenidas!

Editar: Acabo de probar algunas cosas y parece que el formato HTML en xml tiene algunas restricciones:

  • las etiquetas deben escribirse en minúsculas

  • algunas etiquetas que se mencionan aquí no funcionan, por ejemplo <br/>(es posible usar \nen su lugar)

slup
fuente
1
Hace mucho tiempo que lo sé, pero pude usar <br> y no \ n para una nueva línea usando el html para TextView.
Tam
2
¿Esto puede funcionar desde solo xml? Tengo una pequeña recompensa por la respuesta. Tomaría un no como respuestas fácticas en este punto, ya lo he codificado.
danny117
1
Me parece interesante que nadie haya respondido la pregunta. El OP dice que sabe cómo hacerlo con fromHtml (), pero quiere hacerlo directamente en el archivo de diseño (aunque, las razones no son buenas ... siempre tiene una actividad / contexto disponible si está dibujando en la pantalla). Ninguna de las respuestas se sumerge en los efectos de las etiquetas de anclaje tampoco.
lilbyrdie

Respuestas:

481

En caso de que alguien encuentre esto, hay una alternativa mejor que no está documentada (me tropecé después de buscar durante horas y finalmente la encontré en la lista de errores para el SDK de Android). Usted PUEDE incluir HTML puro en strings.xml, siempre y cuando se envuelve en

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

Ejemplo:

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

Luego, en tu código:

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

En mi humilde opinión, es mejor trabajar con varios órdenes de magnitud :-)

Bitbang3r
fuente
26
Solo para agregar, también puede aplicar barras invertidas de escape a los apóstrofes / comillas simples dentro del bloque CDATA, por lo que puede tener cosas como <b> can \ 't </b> en lugar del infinitamente más feo <b> can & apos; t < / b>
Bitbang3r
55
¿Esto todavía funciona? Acabo de probarlo y literalmente muestra <p> y </p>.
Peri Hartman
1
@PeriHartman ¿También hiciste el Html.fromHtml(getString(R.string.nice_html))bit? :)
async
1
¿Dónde hace TextView foo = (TextView) findViewById (R.id.foo); foo.setText (Html.fromHtml (getString (R.string.nice_html))); ¿tengo que irme?
RustyIngles
2
¿Hay alguna manera de evitar "Html.fromHtml"?
Desarrollador de Android
127

Como la respuesta principal aquí sugiere algo incorrecto (o al menos demasiado complicado), creo que esto debería actualizarse, aunque la pregunta es bastante antigua:

Al usar los recursos de String en Android, solo tiene que llamar getString(...)desde un código Java o usarlo android:text="@string/..."en su diseño XML.

Incluso si desea utilizar el marcado HTML en sus cadenas, no tiene que cambiar mucho:

Los únicos personajes que necesita para escapar en sus recursos de cadena son:

  • comillas dobles: se "convierte\"
  • comillas simples: se 'convierte\'
  • ampersand: se &convierte &#38;o&amp;

Eso significa que puede agregar su marcado HTML sin escapar de las etiquetas:

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

Sin embargo, para estar seguro, solo debe usar <b>, <i>y <u>como se enumeran en la documentación.

Si desea utilizar sus cadenas HTML a partir de XML , sólo seguir utilizando android:text="@string/...", no tendrán ningún problema.

La única diferencia es que, si desea usar sus cadenas HTML del código Java , debe usarlas en getText(...)lugar de getString(...)ahora, ya que la primera mantiene el estilo y la segunda simplemente se la quitará.

Es tan fácil como eso. No CDATA, no Html.fromHtml(...).

Sólo necesitará Html.fromHtml(...)si lo hizo codificar sus caracteres especiales en HTML marcado. Úselo con getString(...)entonces. Esto puede ser necesario si desea pasar la Cadena a String.format(...).

Todo esto también se describe en los documentos .

Editar:

No hay diferencia entre getText(...)HTML sin escapes (como he propuesto) o CDATAsecciones y Html.fromHtml(...).

Vea el siguiente gráfico para una comparación:

ingrese la descripción de la imagen aquí

graznar
fuente
El mío lo está quitando. Estoy usando el siguiente código:getResources().getText(R.string.codename)
Si8
3
Para ayudar mejor, necesitaría ver los extractos de Java / XML. Pero como he escrito: Usted sólo es seguro si usted está utilizando <b>, <i>, <u>. Otras etiquetas no siempre son compatibles.
caw
1
Su respuesta funciona y es simple. Simplemente coloque su cadena en strings.xml, con las etiquetas html deseadas, y haga referencia a ella desde su archivo xml de diseño. Usé la etiqueta <sup>.
Peri Hartman
1
La suya es otra solución, no una alternativa a la otra porque no admite todas las etiquetas, como lo hace la otra. No veo ninguna ventaja en esta solución cuando la otra es muy simple.
mobilepotato7
1
Como he experimentado con el uso de "CDATA", tengo un problema, algo como esto, por ejemplo: <! [CDATA [... HTML ...]]> que tiene 22 letras y la parte html tiene 10. así que si usa HTML.fromhtml ( getstring (...)) su texto se mostrará correctamente pero el contenido del texto necesita 22 espacios de letras. Utilicé en listview y vi espacios con malezas. entonces gettext () es MEJOR.
David
16

Escape sus etiquetas HTML ...

<resources>
    <string name="somestring">
        &lt;B&gt;Title&lt;/B&gt;&lt;BR/&gt;
        Content
    </string>
</resources>
ekawas
fuente
Eso es lo que dicen los documentos: developer.android.com/intl/zh-TW/guide/topics/resources/… pero ¿es suficiente para TextViewque muestre HTML?
Macarse
3
He probado esto, y si lo usa desde el código fuente de Java, está bien. Pero si asocia su texto directamente desde el diseño XML, las etiquetas se muestran en la vista de texto (por ejemplo, <B> Título </B> ...)
ZoltanF
Para mostrar el texto en una vista, use la clase [ developer.android.com/reference/android/text/Html.html] , específicamente fromHTML().
ekawas
@ZoltanF tiene razón, usando android: text = "" desde un diseño con HTML mostrará las etiquetas en la cadena.
Andrew Mackenzie
1
Si desea utilizar la cadena HTML directamente desde XML, es posible que no codifican HTML caracteres especiales en la cadena. Sin embargo, si desea utilizar la cadena del código a través Html.fromHTML(), debe codificar los caracteres especiales. ¡Extraño!
caw
11

Android no tiene una especificación para indicar el tipo de cadena de recursos (por ejemplo, texto / sin formato o texto / html). Sin embargo, existe una solución alternativa que permitirá al desarrollador especificar esto dentro del archivo XML.

  1. Defina un atributo personalizado para especificar que el atributo android: text es html.
  2. Use un TextView subclasificado.

Una vez que los defina, puede expresarse con HTML en archivos xml sin tener que volver a llamar a setText (Html.fromHtml (...)). Estoy bastante sorprendido de que este enfoque no sea parte de la API.

Esta solución funciona en la medida en que el simulador de estudio de Android mostrará el texto como HTML renderizado.

ingrese la descripción de la imagen aquí

res / values ​​/ strings.xml (el recurso de cadena como HTML)

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

layout.xml (solo las partes relevantes)

Declare el espacio de nombres del atributo personalizado y agregue el atributo android_ex: isHtml. Utilice también la subclase de 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 (define los atributos personalizados para la subclase)

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

TextViewEx.java (la subclase de 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
fuente
Este enfoque será mejor, si la aplicación utiliza cadenas con formato HTML en varios lugares en lugar de llamar a HTML.fromHtml en cada lugar. La aplicación en sí tendrá dos vistas, una para normal y otra para HTML.
Manju
10

Última actualización:

Html.fromHtml(string);// en desuso después de las versiones de Android N ..

El siguiente código da soporte a Android N y versiones superiores ...

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
fuente
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);
Kawatra disidente
fuente
2

Tengo otro caso cuando no tengo oportunidad de poner CDATA en el xml cuando recibo la cadena HTML de un servidor.

Esto es lo que obtengo de un servidor:

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

Parece ser más complicado pero la solución es mucho más simple.

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

}

¡Espero eso ayude!
Linh

Linh Lino
fuente
44
¿Dónde está la implementación de la función getHTMLContentFromAServer ()
Pallavi