android developer android developer - 3 months ago 19x
Android Question

How to have a SpannableStringBuilder append a span that's inside a formatted string?


Suppose I use SpannableStringBuilder to append multiple stuff into it, and one of them is string that I format from the strings.xml file, which has a span inside:

SpannableStringBuilder stringBuilder = new SpannableStringBuilder ();

final SpannableString span = new SpannableString(...);
span.setSpan(new BackgroundColorSpan(0xff990000), ...,...,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
stringBuilder.append(getString(R.string.string_to_format, span));


The problem

Sadly, formatting such a string removes the span itself, so in my case, there won't be any text with a background color.

This happens on the line of the "getString".

What I've tried

If I just append the span alone (without "getString"), it works fine.

I also tried to investigate Html.fromHtml, but it doesn't seem to support a background color for text anyway.

The question

Is it possible to format a string that has a span, yet still have the span within?

More specifically, the input is a string A from the strings.xml file, which only has a placeholder (no special HTML tags), and another string B that is supposed to replace the placeholder at runtime. The string B should have a highlight for a partial text of itself.

In my case, the highlighted text is a something to search for within string B.


OK, I've found an answer to my special end case, but I'd still like to know if there are better ways.

Here's what I did:

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(string, null, new TagHandler() {
                                    int start;

                                    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();
                                            case "html":
                                                if (!opening)
                                                    output.setSpan(new BackgroundColorSpan(0xff00bbaa), start, start + query.length(), 0);

This is only good for my case, but in the case of general formatting, this won't suffice.