Возможно ли иметь несколько стилей внутри TextView?

можно ли установить несколько стилей для разных фрагментов текста внутри TextView?

например, я устанавливаю текст следующим образом:

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

возможно ли иметь другой стиль для каждого текстового элемента? Е. Г., строка1 полужирный, курсив слово1 и т. д.

руководство разработчика общие задачи и как их выполнять в Android включает в себя выбор, выделение или укладка частей Текст:

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

но это использует явные номера позиций внутри текста. Есть ли более чистый способ сделать это?

17 ответов


в случае, если кому-то интересно знать, как это сделать, вот один из способов: (спасибо Марку снова!)

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

неофициальный список тегов, поддерживаемых этим методом, см. в этой ссылке или такой вопрос: какие теги HTML поддерживаются Android TextView?


попробовать Html.fromHtml(), и отметьте свой текст жирным шрифтом и курсивом HTML-тегов e.g:

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

немного не по теме, но я нашел это слишком полезным, чтобы не упоминать здесь.

что, если мы хотели бы прочитать текст Html из строку.в XML ресурс и, таким образом, сделать его легко локализовать. CDATA сделать это можно:

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

из нашего Java-кода мы могли бы теперь использовать его следующим образом:

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

Я не ожидал, что это сработает. Но это случилось.

надеюсь, что это полезно для некоторых из вас!


Если вам не нравится использовать html, вы можете просто создать стили.xml и использовать его так:

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

список поддерживаемых тэгов:

если вы используете строковый ресурс, вы можете добавить простой стиль, например полужирный или курсив, используя HTML-нотацию. В настоящее время поддерживаются следующие теги: B (полужирный шрифт), I (курсив), U (подчеркивание), TT (monospace),BIG, SMALL, SUP (верхний индекс), SUB (Нижний индекс) и STRIKE (зачеркнуто). Так, например, в res/values/strings.xml вы можете объявить это:

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

(от http://developer.android.com/guide/faq/commontasks.html#selectingtext - ссылка на веб-архив,<resource> опечатка в оригинале!)

он также показывает, что Html.fromHtml на самом деле не требуется в простых случаях.


- Это более легкий вес, чтобы использовать SpannableString вместо разметки html. Это помогает мне видеть визуальные примеры, поэтому вот дополнительный ответ.

enter image description here

Это один 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());

Дальнейшего Изучения

этот пример был первоначально вдохновлен здесь.


я столкнулся с той же проблемой. Я мог бы использовать fromHtml, но теперь я android, а не web, поэтому я решил попробовать это. Мне нужно локализовать это, хотя я дал ему шанс, используя концепцию замены строк. Я установил стиль в TextView как основной стиль, а затем просто отформатировал другие peices.

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

мои строки выглядят это:


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

вот стили:


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

вот мой код, который вызывает мой метод 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);

метод формат:


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

теперь <b> элемент является устаревшим. <strong> отображает как <b> и <em> отображает как <i>.

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

это отлично работает для меня


Если вы хотите добавить стилизованный текст в xml, вы можете создать пользовательское представление, расширяющее TextView и переопределяющее 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);
    }
}

затем вы можете использовать его следующим образом (replace PACKAGE_NAME С вашим именем пакета):

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

вот простой способ сделать это с помощью 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()
    );

результат:

какой-то жирный текст какой-то текст курсивом


Как говорится, использовать TextView.setText(Html.fromHtml(String))

и используйте эти теги в вашей строке в формате 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


Мне Тоже

Как насчет использования красивой разметки с Котлином и Анко -

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


фактически, кроме объекта Html, вы также можете использовать классы типов Spannable, например TextAppearanceSpan или TypefaceSpan и SpannableString togather. Класс Html также использует эти механизмы. Но с классами типов Spannable у вас больше свободы.


это может быть так же просто, как использовать метод length() строки:

  1. разделить текстовую строку в xml-файле строк на столько подстрок (отдельные строки с точки зрения Android) , сколько вам нужно разных стилей, так что это может быть похоже:str1 выглядит следующим образом, стр2, стр3 (как в вашем случае), которые вместе являются единым целым строку, которую вы используете.

  2. а затем просто следуйте методу "Span", просто как вы представили свой код , но вместо одной строки объедините все подстроки, объединив их в один, каждый с другим пользовательским стилем.

вы все еще используете числа, однако не напрямую - они больше не принимают жестко закодированную форму (как в вашем коде), но они заменяются методами комбинированной длины () (обратите внимание на две звезды, предшествующие и суффиксирующие str.длина() в место абсолютного количества в extuinguish в изменить):

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

для первой строки, потом .length () + 1, str.длина() + стр2.length () для второго размера строки и так далее со всеми подстроками, вместо, например, 0,7 или 8,19 и так далее...


используя вспомогательный Spannable класс как Строковые Ресурсы Android акций внизу страницы. Вы можете подойти к этому, создавCharSquences и дать им стиль.

но в Примере, который они нам дают, это просто жирный, курсив и даже цвет текста. Мне нужно было обернуть несколько стилей вCharSequence для того, чтобы установить их в TextView. Итак, к этому классу (я назвал его CharSequenceStyles) Я только что добавил эту функцию.

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

и в представлении я добавил этот.

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

надеюсь, это поможет вам!


Spanny сделать SpannableString проще в использовании.

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

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

}

и это все, теперь только поместите его в свой 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" />

С вашей строкой Html

<string name="example_html">
<![CDATA[
<b>Author:</b> Mr Donuthead<br/>
<b>Contact:</b> me@donut.com<br/>
<i>Donuts for life </i>
]]>