web-dev-qa-db-fra.com

Est-il possible d'avoir plusieurs styles dans un TextView?

Est-il possible de définir plusieurs styles pour différents morceaux de texte dans un TextView?

Par exemple, je règle le texte comme suit:

tv.setText(line1 + "\n" + line2 + "\n" + Word1 + "\t" + Word2 + "\t" + Word3);

Est-il possible d'avoir un style différent pour chaque élément de texte? Exemple: ligne1 gras, Word1 italique, etc.

Le guide du développeur tâches courantes et comment les utiliser dans Android inclut sélection, mise en surbrillance ou style de portions de texte :

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

Mais cela utilise des numéros de position explicites à l'intérieur du texte. Y a-t-il une manière plus propre de faire ceci?

525
Legend

Au cas où quelqu'un se demanderait comment faire cela, voici une solution: (Merci encore à Mark!)

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

Pour obtenir une liste non officielle des balises prises en charge par cette méthode, reportez-vous à la section ce lien ou à cette question: Quelles balises HTML sont prises en charge par Android TextView?

685
Legend

Essayez Html.fromHtml() et marquez votre texte avec des balises HTML en gras et en italique, par exemple:

Spanned text = Html.fromHtml("This mixes <b>bold</b> and <i>italic</i> stuff");
textView.setText(text);
211
CommonsWare

Légèrement hors sujet, mais j'ai trouvé cela trop utile pour ne pas être mentionné ici.

Et si nous aimerions lire le texte HTML de string.xml ressource et facilite donc la localisation. CDATA rendre cela possible:

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

À partir de notre code Java, nous pourrions maintenant l'utiliser comme ceci:

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

Je ne m'attendais pas à ce que cela fonctionne. Mais ça l'a fait.

J'espère que c'est utile pour certains d'entre vous!

184
Ben

Si vous ne souhaitez pas utiliser le langage HTML, vous pouvez simplement créer un fichier styles.xml et l'utiliser comme suit:

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);
116
Kent Andersen

Il est plus léger d’utiliser un SpannableString au lieu d’un balisage HTML. Cela me permet de voir des exemples visuels, voici donc une réponse supplémentaire.

enter image description here

Ceci est un simple 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());

Une étude plus approfondie

Cet exemple a été inspiré à l'origine de ici .

46
Suragch

La liste des tags supportés est la suivante:

Si vous utilisez une ressource de chaîne, vous pouvez ajouter des styles simples, tels que gras ou italique, en utilisant la notation HTML. Les tags actuellement supportés sont: B (gras), I (italique), U (souligné), TT (monospace), BIG, SMALL, SUP (exposant), SUB (indice) et STRIKE (barré). Ainsi, par exemple, dans res/values/strings.xml, vous pouvez déclarer ceci:

<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 - Lien Web Archive, <resource> la faute de frappe est dans l'original!)

Cela montre également que Html.fromHtml n'est pas vraiment nécessaire dans les cas simples.

39
Jon

Je rencontrais le même problème. Je pourrais utiliser fromHtml, mais je suis Android maintenant, pas sur le Web. J'ai donc décidé de l'essayer. Je dois localiser cela cependant, donc je l'ai essayé en utilisant le concept de remplacement de chaîne. Je règle le style sur le TextView comme étant le style principal, puis formate simplement les autres peices.

J'espère que cela aidera les autres qui cherchent à faire la même chose - je ne sais pas pourquoi ce n'est pas plus facile dans le cadre.

Mes cordes ressemblent à ceci:


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

Voici les styles:


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

Voici mon code qui appelle ma méthode 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);

La méthode de formatage:


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
farcrats

Maintenant, l'élément <b> est obsolète. <strong> s'affiche sous la forme <b> et <em> s'affiche sous la forme <i>.

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

cela fonctionne bien pour moi

12
Sandeep P

Voici un moyen facile de le faire en utilisant 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()
    );

Résultat:

Du texte en gras Du texte en italique

6
Ilya Gazman

Comme indiqué, utilisez TextView.setText(Html.fromHtml(String))

Et utilisez ces balises dans votre chaîne au format 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
Andrew Gallasch

Si vous souhaitez pouvoir ajouter le texte stylé au format xml, vous pouvez créer une vue personnalisée qui étend TextView et remplacer le paramètre 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);
    }
}

Ensuite, vous pouvez l’utiliser comme ceci (remplacez PACKAGE_NAME par votre nom de paquet):

<PACKAGE_NAME.HTMLStyledTextView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:text="<![CDATA[
        <b>Bolded Text:</b> Non-Bolded Text
    ]]>"
/>
6
bcorso

Moi aussi

Pourquoi ne pas utiliser de jolis balisages avec Kotlin et 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)
            }
        }
    }
}

Created with Beautiful Markup

2
Himanshu

Oui, il est possible d’utiliser SpannedString. Si vous utilisez Kotlin, il est encore plus facile de le faire en utilisant core-ktx, car il fournit un langage spécifique au domaine (DSL) pour le faire:

    val string: SpannedString = buildSpannedString {
        bold {
            append("1111")
        }
        append("Devansh")     
    }

Plus d'options fournies par ce logiciel sont:

append("Hello There")
bold {
    append("bold")
    italic {
        append("bold and italic")
        underline {
            append("then some text with underline")
        }
    }
}

Enfin, vous pouvez simplement:

textView.text = string
1
Devansh Maurya

Spanny Rendez SpannableString plus facile à utiliser.

Spanny spanny = new Spanny("Underline text", new UnderlineSpan())
                .append("\nRed text", new ForegroundColorSpan(Color.RED))
                .append("\nPlain text");
textView.setText(spanny)
0
Desmond Lua

Utilisation d'une classe spannable auxiliaire sous forme de ressources de chaîne Android au bas de la page Web. Vous pouvez aborder cela en créantCharSquences et en leur donnant un style.

Mais dans l'exemple qu'ils nous donnent, c'est juste pour gras, italique et même coloriser le texte. Je devais envelopper plusieurs styles dans aCharSequence afin de les définir dans un TextView. Donc, à cette classe (je l'ai nommée CharSequenceStyles), je viens d'ajouter cette fonction.

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

Et dans la vue j'ai ajouté ceci.

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

J'espère que cela vous aidera!

0
MontDeska

En fait, à l'exception de l'objet HTML, vous pouvez également utiliser les classes de type Spannable, par exemple. TextAppearanceSpan ou TypefaceSpan et SpannableString togather. La classe HTML utilise également ces mécanismes. Mais avec les classes de type Spannable, vous avez plus de liberté.

0
Clock ZHONG

Comme Jon dit , pour moi, c'est la meilleure solution et vous n'avez pas besoin de définir de texte à l'exécution, utilisez uniquement cette classe personnalisée 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);
  }

}

et c'est tout, maintenant ne le mettez que dans votre 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" />

avec votre chaîne html

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

Cela peut être aussi simple que de tirer parti de la méthode String's length ():

  1. Fractionnez la chaîne de texte du fichier XML Strings en autant de sous-chaînes (une chaîne distincte du point de vue d'Android) que vous avez besoin de plusieurs styles, pour que cela puisse ressembler à ceci: str1, str2, str (comme dans votre cas), qui, une fois réunis, constituent la chaîne unique que vous utilisez.

  2. Suivez ensuite simplement la méthode "Span", comme vous l'avez présenté avec votre code - mais au lieu d'une seule chaîne, combinez toutes les sous-chaînes en les fusionnant en une seule, chacune avec un style personnalisé différent.

Vous utilisez toujours les nombres, mais pas directement - ils ne prennent plus maintenant une forme codée en dur (comme dans votre code), mais ils sont remplacés par les méthodes combinées length () (notez deux étoiles précédentes et suffixant le str. length () à la place du nombre absolu pour éteindre le changement):

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

pour la première taille de chaîne, alors str.length () + 1, str.length () + str2.length () pour la deuxième taille de chaîne, et ainsi de suite avec toutes les sous-chaînes au lieu de p. 0,7 ou 8,19 et ainsi de suite ...

0
forsberg