Es posible tener varios estilos dentro de un TextView?


¿Es posible establecer varios estilos para diferentes piezas de texto dentro de TextView?

Por ejemplo, estoy configurando el texto de la siguiente manera:

tv.setText(line1 + "\n" + line2 + "\n" + word1 + "\t" + word2 + "\t" + word3);

Es posible tener un estilo diferente para cada elemento de texto? Por ejemplo, línea 1 negrita, palabra 1 cursiva, etc.

Las Tareas Comunes de la guía para desarrolladores y Cómo Hacerlas en Android incluyen Seleccionando, Resaltando o Estilizando Porciones de Texto :

// Get our EditText object.
EditText vw = (EditText)findViewById(R.id.text);

// Set the EditText's text.
vw.setText("Italic, highlighted, bold.");

// If this were just a TextView, we could do:
// vw.setText("Italic, highlighted, bold.", TextView.BufferType.SPANNABLE);
// to force it to use Spannable storage so styles can be attached.
// Or we could specify that in the XML.

// Get the EditText's internal text storage
Spannable str = vw.getText();

// Create our span sections, and assign a format to each.
str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
str.setSpan(new BackgroundColorSpan(0xFFFFFF00), 8, 19, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 21, str.length() - 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Pero que utiliza la posición explícita números dentro del texto. ¿Hay una forma más limpia de hacer esto?

Author: blahdiblah, 2009-10-07

17 answers

En caso de que alguien se pregunte cómo hacer esto, aquí hay una manera: (¡Gracias a Mark nuevamente!)

mBox = new TextView(context);
mBox.setText(Html.fromHtml("<b>" + title + "</b>" +  "<br />" + 
            "<small>" + description + "</small>" + "<br />" + 
            "<small>" + DateAdded + "</small>"));

Para obtener una lista no oficial de etiquetas soportadas por este método, consulte este enlace o esta pregunta: ¿Qué etiquetas HTML son soportadas por Android TextView?

 678
Author: Legend,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:30

Prueba Html.fromHtml() y marca tu texto con etiquetas HTML en negrita y cursiva, por ejemplo:

Spanned text = Html.fromHtml("This mixes <b>bold</b> and <i>italic</i> stuff");
textView.setText(text);
 207
Author: CommonsWare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-31 21:30:15

Un poco fuera de tema, pero encontré esto demasiado útil para no ser mencionado aquí.

Y si nos gustaría leer el texto Html de la cadena .xml y así hacer que sea fácil de localizar. CDATA hacer esto posible:

<string name="my_text">
  <![CDATA[
    <b>Autor:</b> Mr Nice Guy<br/>
    <b>Contact:</b> [email protected]<br/>
    <i>Copyright © 2011-2012 Intergalactic Spacebar Confederation </i>
  ]]>
</string> 

A partir de nuestro código Java ahora podríamos utilizarlo de la siguiente manera:

TextView tv = (TextView) findViewById(R.id.myTextView);
tv.setText(Html.fromHtml(getString(R.string.my_text))); 

No esperaba que esto funcionara. Pero lo hizo.

Espero que sea útil para algunos de ustedes!

 177
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-03 11:20:44

Si no tienes ganas de usar html, puedes crear un estilo.xml y úsalo así:

TextView tv = (TextView) findViewById(R.id.textview);
SpannableString text = new SpannableString(myString);

text.setSpan(new TextAppearanceSpan(getContext(), R.style.myStyle), 0, 5, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
text.setSpan(new TextAppearanceSpan(getContext(), R.style.myNextStyle), 6, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

tv.setText(text, TextView.BufferType.SPANNABLE);
 106
Author: Kent Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-29 12:46:49

La lista de etiquetas soportadas es:

Si utiliza un recurso de cadena, puede agregar algunos estilos simples, como negrita o cursiva utilizando la notación HTML. Actualmente etiquetas compatibles son: B (negrita) I (cursiva) U (subrayado), TT (monospace), BIG, SMALL, SUP (superíndice), SUB (subíndice), y STRIKE (tachado). Así, por ejemplo, en res/values/strings.xml podrías declarar esto:

<resource>
    <string id="@+id/styled_welcome_message">We are <b><i>so</i></b> glad to see you.</string>
</resources>

(De http://developer.android.com/guide/faq/commontasks.html#selectingtext - Enlace al archivo web, <resource> el error tipográfico está en el original!)

También muestra que Html.fromHtml no es realmente necesario en casos simples.

 38
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-08 18:29:19

Es más ligero usar un SpannableString en lugar de un marcado html. Me ayuda ver ejemplos visuales, así que aquí hay una respuesta complementaria.

introduzca la descripción de la imagen aquí

Este es un único TextView.

// set the text
SpannableString s1 = new SpannableString("bold\n");
SpannableString s2 = new SpannableString("italic\n");
SpannableString s3 = new SpannableString("foreground color\n");
SpannableString s4 = new SpannableString("background color\n");
SpannableString s5 = new SpannableString("underline\n");
SpannableString s6 = new SpannableString("strikethrough\n");
SpannableString s7 = new SpannableString("bigger\n");
SpannableString s8 = new SpannableString("smaller\n");
SpannableString s9 = new SpannableString("font\n");
SpannableString s10 = new SpannableString("URL span\n");
SpannableString s11 = new SpannableString("clickable span\n");
SpannableString s12 = new SpannableString("overlapping spans\n");

// set the style
int flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
s1.setSpan(new StyleSpan(Typeface.BOLD), 0, s1.length(), flag);
s2.setSpan(new StyleSpan(Typeface.ITALIC), 0, s2.length(), flag);
s3.setSpan(new ForegroundColorSpan(Color.RED), 0, s3.length(), flag);
s4.setSpan(new BackgroundColorSpan(Color.YELLOW), 0, s4.length(), flag);
s5.setSpan(new UnderlineSpan(), 0, s5.length(), flag);
s6.setSpan(new StrikethroughSpan(), 0, s6.length(), flag);
s7.setSpan(new RelativeSizeSpan(2), 0, s7.length(), flag);
s8.setSpan(new RelativeSizeSpan(0.5f), 0, s8.length(), flag);
s9.setSpan(new TypefaceSpan("monospace"), 0, s9.length(), flag);
s10.setSpan(new URLSpan("https://developer.android.com"), 0, s10.length(), flag);
s11.setSpan(new ClickableSpan() {
    @Override
    public void onClick(View widget) {
        Toast.makeText(getApplicationContext(), "Span clicked", Toast.LENGTH_SHORT).show();
    }
}, 0, s11.length(), flag);
s12.setSpan(new ForegroundColorSpan(Color.RED), 0, 11, flag);
s12.setSpan(new BackgroundColorSpan(Color.YELLOW), 4, s12.length(), flag);
s12.setSpan(new UnderlineSpan(), 4, 11, flag);

// build the string
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(s1);
builder.append(s2);
builder.append(s3);
builder.append(s4);
builder.append(s5);
builder.append(s6);
builder.append(s7);
builder.append(s8);
builder.append(s9);
builder.append(s10);
builder.append(s11);
builder.append(s12);

// set the text view with the styled text
textView.setText(builder);
// enables clicking on spans for clickable span and url span
textView.setMovementMethod(LinkMovementMethod.getInstance());

Estudio adicional

Este ejemplo fue originalmente inspirado de aquí .

 36
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:30

Me estaba topando con el mismo problema. Podría usar fromHtml, pero ahora soy Android, no web, así que decidí probar esto. Sin embargo, tengo que localizar esto, así que le di una oportunidad usando el concepto de reemplazo de cadenas. Establezco el estilo en TextView para que sea el estilo principal, luego simplemente formateo los otros peices.

Espero que esto ayude a otros que buscan hacer lo mismo - no se por qué esto no es más fácil en el framework.

Mis cadenas se ven así:


<string name="my_text">{0} You will need a {1} to complete this assembly</string>
<string name="text_sub0">1:</string>
<string name="text_sub1">screwdriver, hammer, and measuring tape</string>

Aquí están los estilos:


<style name="MainStyle">
    <item name="android:textSize">@dimen/regular_text</item>
    <item name="android:textColor">@color/regular_text</item>
</style>
<style name="style0">
    <item name="android:textSize">@dimen/paragraph_bullet</item>
    <item name="android:textColor">@color/standout_text</item>
    <item name="android:textStyle">bold</item>
</style>
<style name="style1">
    <item name="android:textColor">@color/standout_light_text</item>
    <item name="android:textStyle">italic</item>
</style>

Aquí está mi código que llama a mi método formatStyles:


SpannableString formattedSpan = formatStyles(getString(R.string.my_text), getString(R.string.text_sub0), R.style.style0, getString(R.string.main_text_sub1), R.style.style1);
textView.setText(formattedSpan, TextView.BufferType.SPANNABLE);

El método de formato:


private SpannableString formatStyles(String value, String sub0, int style0, String sub1, int style1)
{
    String tag0 = "{0}";
    int startLocation0 = value.indexOf(tag0);
    value = value.replace(tag0, sub0);

    String tag1 = "{1}";
    int startLocation1 = value.indexOf(tag1);
    if (sub1 != null && !sub1.equals(""))
    {
        value = value.replace(tag1, sub1);
    }

    SpannableString styledText = new SpannableString(value);
    styledText.setSpan(new TextAppearanceSpan(getActivity(), style0), startLocation0, startLocation0 + sub0.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    if (sub1 != null && !sub1.equals(""))
    {
        styledText.setSpan(new TextAppearanceSpan(getActivity(), style1), startLocation1, startLocation1 + sub1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    return styledText;
}
 16
Author: farcrats,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-07 23:22:09

Ahora el elemento <b> está obsoleto. <strong> hace como <b>, y <em> hace como <i>.

tv.setText(Html.fromHtml("<strong>bold</strong> and <em>italic</em> "));

Esto funciona bien para mí

 12
Author: Sandy09,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-05 16:30:46

Si desea poder agregar el texto con estilo en xml, puede crear una vista personalizada que extienda TextView y anule setText ():

public class HTMLStyledTextView extends TextView
{
    public HTMLStyledTextView(Context context) {
        super(context);
    }

    public HTMLStyledTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public HTMLStyledTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setText(CharSequence text, BufferType type)
    {
       super.setText(Html.fromHtml(text.toString()), type);
    }
}

Entonces, puede usarlo de esta manera (reemplazar PACKAGE_NAME con su nombre de paquete):

<PACKAGE_NAME.HTMLStyledTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="<![CDATA[
        <b>Bolded Text:</b> Non-Bolded Text
    ]]>"
/>
 6
Author: bcorso,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-20 00:07:03

Aquí hay una manera fácil de hacerlo usando HTMLBuilder

    myTextView.setText(new HtmlBuilder().
                    open(HtmlBuilder.Type.BOLD).
                    append("Some bold text ").
                    close(HtmlBuilder.Type.BOLD).
                    open(HtmlBuilder.Type.ITALIC).
                    append("Some italic text").
                    close(HtmlBuilder.Type.ITALIC).
                    build()
    );

Resultado:

Texto en negrita Algún texto en cursiva

 6
Author: Ilya Gazman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-03 07:27:14

Como se ha indicado, use TextView.setText(Html.fromHtml(String))

Y use estas etiquetas en su cadena con formato Html:

<a href="...">
<b>
<big>
<blockquote>
<br>
<cite>
<dfn>
<div align="...">
<em>
<font size="..." color="..." face="...">
<h1>
<h2>
<h3>
<h4>
<h5>
<h6>
<i>
<img src="...">
<p>
<small>
<strike>
<strong>
<sub>
<sup>
<tt>
<u>

Http://commonsware.com/blog/Android/2010/05/26/html-tags-supported-by-textview.html

 6
Author: Andrew Gallasch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-03 11:45:51

Yo también

¿Qué tal usar un hermoso marcado con Kotlin y Anko -

import org.jetbrains.anko.*
override fun onCreate(savedInstanceState: Bundle?) {
    title = "Created with Beautiful Markup"
    super.onCreate(savedInstanceState)

    verticalLayout {
        editText {
            hint = buildSpanned {
                append("Italic, ", Italic)
                append("highlighted", backgroundColor(0xFFFFFF00.toInt()))
                append(", Bold", Bold)
            }
        }
    }
}

Creado con Beautiful Markup

 1
Author: Himanshu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-14 08:00:58

De hecho, excepto el objeto Html, también puede usar las clases de tipo Spannable, por ejemplo TextAppearanceSpan o TypefaceSpan y SpannableString togather. La clase Html también utiliza estos mecanismos. Pero con las clases de tipo Spannable, tienes más libertad.

 0
Author: Clock ZHONG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-11 10:01:21

Podría ser tan simple como aprovechar el método length() de la cadena:

  1. Divida la cadena de texto en el archivo XML de Cadenas en tantas sub-cadenas (cadenas separadas desde el punto de vista de Android) como necesite diferentes estilos, por lo que podría ser como: str1, str2, str3 (como en su caso), que cuando se unen son la cadena única completa que utiliza.

  2. Y luego simplemente siga el método "Span", al igual que presentó con su código - pero en lugar de una sola cadena, combine todas las subcadenas fusionándolas en una sola, cada una con un estilo personalizado diferente.

Todavía usas los números, sin embargo no directamente - ya no toman una forma hardcoded (como en tu código) ahora, pero están siendo sustituidos por los métodos combinados length () (nota dos estrellas precediendo y sufijando el str.length () en lugar del número absoluto para extuinguir el cambio):

str.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, **str.length()**, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Para el primer tamaño de cadena, entonces str.length () + 1, str.length () + str2.length () para el tamaño de la segunda cadena, y así sucesivamente con todas las subcadenas, en lugar de por ejemplo 0,7 u 8,19 y así sucesivamente...

 0
Author: forsberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-11 09:30:58

Usando una clase Spannable auxiliar como Android String Resources comparte en la parte inferior de la página web. Puedes acercarte a esto creandoCharSquences y dándoles un estilo.

Pero en el ejemplo que nos dan, es solo para negrita, cursiva, e incluso colorear texto. Necesitaba envolver varios estilos en un CharSequence para establecerlos en un TextView. Así que a esa Clase (la nombré CharSequenceStyles) acabo de agregar esta función.

public static CharSequence applyGroup(LinkedList<CharSequence> content){
    SpannableStringBuilder text = new SpannableStringBuilder();
    for (CharSequence item : content) {
        text.append(item);
    }
    return text;
}

Y en la vista agregué esto.

            message.push(postMessageText);
            message.push(limitDebtAmount);
            message.push(pretMessageText);
            TextView.setText(CharSequenceStyles.applyGroup(message));

Espero que esta ayuda ¡tú!

 0
Author: MontDeska,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-07 23:15:18

Spanny hace SpannableString más fácil de usar.

Spanny spanny = new Spanny("Underline text", new UnderlineSpan())
                .append("\nRed text", new ForegroundColorSpan(Color.RED))
                .append("\nPlain text");
textView.setText(spanny)
 0
Author: Desmond Lua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-17 15:53:22

Como dijo Jon , para mí esta es la mejor solución y no necesita establecer ningún texto en tiempo de ejecución, solo use esta clase personalizada HtmlTextView

public class HtmlTextView extends TextView {

  public HtmlTextView(Context context) {
      super(context);
  }

  public HtmlTextView(Context context, AttributeSet attrs) {
      super(context, attrs);
  }

  public HtmlTextView(Context context, AttributeSet attrs, int defStyleAttr) 
  {
      super(context, attrs, defStyleAttr);
  }

  @TargetApi(21)
  public HtmlTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
      super(context, attrs, defStyleAttr, defStyleRes);
  }

  @Override
  public void setText(CharSequence s,BufferType b){
      super.setText(Html.fromHtml(s.toString()),b);
  }

}

Y eso es todo, ahora solo ponlo en tu XML

<com.fitc.views.HtmlTextView
    android:id="@+id/html_TV"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/example_html" />

Con su cadena Html

<string name="example_html">
<![CDATA[
<b>Author:</b> Mr Donuthead<br/>
<b>Contact:</b> [email protected]<br/>
<i>Donuts for life </i>
]]>

 0
Author: AWolfsdorf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-18 12:46:25