如何让 SpannableStringBuilder 附加一个位于格式化字符串内的跨度?
How to have a SpannableStringBuilder append a span that's inside a formatted string?
背景
假设我使用 SpannableStringBuilder 将多个内容附加到其中,其中之一是我从 strings.xml 文件格式化的字符串,其中有一个跨度:
SpannableStringBuilder stringBuilder = new SpannableStringBuilder ();
stringBuilder.append(...)...
final SpannableString span = new SpannableString(...);
span.setSpan(new BackgroundColorSpan(0xff990000), ...,...,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.append(getString(R.string.string_to_format, span));
stringBuilder.append(...)...
textView.setText(stringBuilder);
问题
遗憾的是,格式化这样的字符串会删除跨度本身,所以在我的例子中,不会有任何带有背景颜色的文本。
这发生在 "getString" 的线上。
我试过的
如果我只附加跨度(没有 "getString"),它工作正常。
我也尝试调查 Html.fromHtml,但它似乎不支持文本的背景颜色。
问题
是否可以格式化具有跨度但仍包含跨度的字符串?
更具体地说,输入是来自 strings.xml 文件的字符串 A,它只有一个占位符(没有特殊的 HTML 标记),以及另一个应该替换占位符的字符串 B在运行时。字符串 B 应突出显示其自身的部分文本。
在我的例子中,突出显示的文本是要在字符串 B 中搜索的内容。
格式化一个跨越的字符串可能是不可能的,因为它仍然使用 String.format() 最后格式化一个字符串,它是一个 Java API,而 Span 是 Android API.
但我认为您可以改用 html 字符串。看看这个文档Styling with HTML markup.
例如:
String str = "Hi <strong><font color=\"#00bbaa\">%s</font></strong>, Welcome to <em><font color=\"#FF4081\">%s</font></em>";
String text = String.format(str, "Lucy", "Android");
Spanned spanned = Html.fromHtml(text);
// after Html.fromHtml(), you can still change the Span
SpannableString spannableString = new SpannableString(spanned);
spannableString.setSpan(new BackgroundColorSpan(0xff990000), 0, 2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
结果
如果您想将字符串放在 string.xml 中,您可能需要将“<”更改为“<”,将“%s”更改为“%1$s”。
<string name="from_offical">Hello <strong><font color="#00bbaa">%1$s</font></strong>, Welcome to <em><font color="#00bbaa">%2$s</font></em></string>
好的,我已经找到了我的特殊最终案例的答案,但我仍然想知道是否有更好的方法。
这是我所做的:
String stringToSearchAt=...
String query=...
int queryIdx = stringToSearchAt.toLowerCase().indexOf(query);
stringToSearchAt= stringToSearchAt.substring(0, queryIdx + query.length()) + "<bc/>" + stringToSearchAt.substring(queryIdx + query.length());
final String formattedStr=getString(..., stringToSearchAt);
stringBuilder.append(Html.fromHtml(formattedStr, null, new TagHandler() {
int start;
@Override
public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
switch (tag) {
case "bc":
if (!opening)
start = output.length() - query.length();
break;
case "html":
if (!opening)
output.setSpan(new BackgroundColorSpan(0xff00bbaa), start, start + query.length(), 0);
}
}
}));
这仅适用于我的情况,但在一般格式化的情况下,这还不够。
背景
假设我使用 SpannableStringBuilder 将多个内容附加到其中,其中之一是我从 strings.xml 文件格式化的字符串,其中有一个跨度:
SpannableStringBuilder stringBuilder = new SpannableStringBuilder ();
stringBuilder.append(...)...
final SpannableString span = new SpannableString(...);
span.setSpan(new BackgroundColorSpan(0xff990000), ...,...,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.append(getString(R.string.string_to_format, span));
stringBuilder.append(...)...
textView.setText(stringBuilder);
问题
遗憾的是,格式化这样的字符串会删除跨度本身,所以在我的例子中,不会有任何带有背景颜色的文本。
这发生在 "getString" 的线上。
我试过的
如果我只附加跨度(没有 "getString"),它工作正常。
我也尝试调查 Html.fromHtml,但它似乎不支持文本的背景颜色。
问题
是否可以格式化具有跨度但仍包含跨度的字符串?
更具体地说,输入是来自 strings.xml 文件的字符串 A,它只有一个占位符(没有特殊的 HTML 标记),以及另一个应该替换占位符的字符串 B在运行时。字符串 B 应突出显示其自身的部分文本。
在我的例子中,突出显示的文本是要在字符串 B 中搜索的内容。
格式化一个跨越的字符串可能是不可能的,因为它仍然使用 String.format() 最后格式化一个字符串,它是一个 Java API,而 Span 是 Android API.
但我认为您可以改用 html 字符串。看看这个文档Styling with HTML markup.
例如:
String str = "Hi <strong><font color=\"#00bbaa\">%s</font></strong>, Welcome to <em><font color=\"#FF4081\">%s</font></em>";
String text = String.format(str, "Lucy", "Android");
Spanned spanned = Html.fromHtml(text);
// after Html.fromHtml(), you can still change the Span
SpannableString spannableString = new SpannableString(spanned);
spannableString.setSpan(new BackgroundColorSpan(0xff990000), 0, 2, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
textView.setText(spannableString);
结果
如果您想将字符串放在 string.xml 中,您可能需要将“<”更改为“<”,将“%s”更改为“%1$s”。
<string name="from_offical">Hello <strong><font color="#00bbaa">%1$s</font></strong>, Welcome to <em><font color="#00bbaa">%2$s</font></em></string>
好的,我已经找到了我的特殊最终案例的答案,但我仍然想知道是否有更好的方法。
这是我所做的:
String stringToSearchAt=...
String query=...
int queryIdx = stringToSearchAt.toLowerCase().indexOf(query);
stringToSearchAt= stringToSearchAt.substring(0, queryIdx + query.length()) + "<bc/>" + stringToSearchAt.substring(queryIdx + query.length());
final String formattedStr=getString(..., stringToSearchAt);
stringBuilder.append(Html.fromHtml(formattedStr, null, new TagHandler() {
int start;
@Override
public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
switch (tag) {
case "bc":
if (!opening)
start = output.length() - query.length();
break;
case "html":
if (!opening)
output.setSpan(new BackgroundColorSpan(0xff00bbaa), start, start + query.length(), 0);
}
}
}));
这仅适用于我的情况,但在一般格式化的情况下,这还不够。