是否有可能为一个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);

但这使用了文本中的显式位置编号。有更干净的方法吗?


当前回答

如果你不喜欢使用html,你可以创建一个styles.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);

其他回答

使用SpannableString是实现这一目标的好方法

我使用了几个函数使其易于应用,我将首先解释每个函数的思想,然后显示代码:

String.getAllIndexOf(pattern: String): This will search the patter on the string and return an index list of where the pattern start. Ex: given the string "abcdefabc" and I call the method passing the "abc" as the searched pattern, the method should return the list: listOf(0, 6) The is a class to receive the pattern and a list of styles (in case you desire to apply different styles to the same pattern in sequence) SpannableString.applyStyle(context: Context, vararg patternAndStyles: PatternAndStyles): This will apply the styles to the given patterns


现在,在代码上:

getAllIndexOf fun String.getAllIndexOf(pattern: String): List<Int> { val allRecordsOfText = mutableListOf<Int>() var index = 0 while(index >= 0) { val newStart = if (allRecordsOfText.isEmpty()) { 0 } else { allRecordsOfText.last() + pattern.length } index = this.subSequence(newStart, this.length).indexOf(pattern) if (index >= 0) { allRecordsOfText.add(newStart + index) } } return allRecordsOfText.toList() } Class to receive the pattern and styles @Parcelize class PatternAndStyles( val pattern: String, val styles: List<Int> ) : Parcelable applyStyle fun SpannableString.applyStyle(context: Context, vararg patternAndStyles: PatternAndStyles) { for (patternStyle in patternAndStyles.toList()) { this.toString().getAllIndexOf(patternStyle.pattern).forEachIndexed { index, start -> val end = start + patternStyle.pattern.length val styleIndex = if (patternStyle.styles.size > index) index else patternStyle.styles.size - 1 this.setSpan( TextAppearanceSpan(context, patternStyle.styles[styleIndex]), start, end, SPAN_EXCLUSIVE_EXCLUSIVE ) } } } How to use it in the end val stringToApplyStyle = "abc def abc def" val text = SpannableString(stringToApplyStyle) text.applyStyle( this.applicationContext, PatternAndStyles("abc", listOf(R.style.Style1, R.style.Style2)), PatternAndStyles("def", listOf(R.style.Style3)) ) The output:

当它被传递给样式到模式“abc”时,两者都被使用 但是在模式“def”中,第二条记录重用了列表中给出的最后一个样式

有点离题,但我觉得这个太有用了,不能不在这里提一下。

如果我们想从string.xml资源中读取Html文本,从而使其易于本地化。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标记的粗体或斜体。目前支持的标签有:B(粗体)、I(斜体)、U(下划线)、TT(单行)、BIG、SMALL、SUP(上标)、SUB(下标)和STRIKE(划线)。例如,在res/values/strings.xml中,你可以这样声明: <资源> <string id="@+id/styled_welcome_message">We are <b><i>so</i></b> glad to see you.</string> > < /资源

(来自http://developer.android.com/guide/faq/commontasks.html#selectingtext - Web Archive链接,<资源>错别字是在原始!)

它还表明在简单的情况下并不真正需要Html.fromHtml。

如果你想在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);
    }
}

然后,你可以像这样使用它(用你的包名替换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
    ]]>"
/>

这可能就像利用String的length()方法一样简单:

将Strings XML文件中的文本字符串拆分为许多子字符串(从Android的角度来看是一个单独的字符串),因为你需要不同的风格,所以它可以像:str1, str2, str3(在你的情况下),当连接在一起时,就是你使用的整个单一字符串。 然后简单地遵循“Span”方法,就像您在代码中展示的那样——但不是单个字符串,而是将所有子字符串合并为单个字符串,每个子字符串具有不同的自定义样式。

你仍然使用这些数字,但不是直接使用——它们现在不再采用硬编码形式(就像在你的代码中那样),但它们被组合length()方法所取代(注意在str.length()之前和后面加上两颗星来代替绝对数字,以消除变化):

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

对于第一个字符串大小,则str.length() + 1,对于第二个字符串大小,则str.length() + str2.length(),等等,所有的子字符串,而不是例如0,7或8,19等等…