Как сделать так, чтобы SpannableStringBuilder добавлял диапазон, который находится внутри отформатированной строки?

Задний план

Предположим, я использую 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, но, похоже, он все равно не поддерживает цвет фона для текста.

Вопрос

Можно ли отформатировать строку, которая имеет диапазон, но все еще имеет диапазон внутри?

Точнее, входными данными является строка A из файла strings.xml, которая имеет только заполнитель (без специальных тегов HTML), и еще одна строка B, которая должна заменить заполнитель во время выполнения. Строка B должна иметь подсветку для частичного текста самой себя.

В моем случае выделенный текст — это то, что нужно искать в строке B.


person android developer    schedule 04.07.2016    source источник
comment
После Html.fromHtml() вы все еще можете изменить диапазон, как обычный SpannableString.   -  person Harlan    schedule 09.07.2016
comment
Я не использовал Html.fromHtml. Пожалуйста, объясните, что вы имеете в виду.   -  person android developer    schedule 09.07.2016


Ответы (2)


Хорошо, я нашел ответ на свой особый конечный случай, но мне все же хотелось бы знать, есть ли лучшие способы.

Вот что я сделал:

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

Это хорошо только для моего случая, но в случае общего форматирования этого будет недостаточно.

person android developer    schedule 09.07.2016

форматирование составной строки может быть невозможным, потому что он по-прежнему использует String.format() для окончательного форматирования строки, это API Java, а Span - Android API.

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

Например:

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 &lt;strong>&lt;font color="#00bbaa">%1$s&lt;/font>&lt;/strong>, Welcome to &lt;em>&lt;font color="#00bbaa">%2$s&lt;/font>&lt;/em></string>
person Harlan    schedule 09.07.2016
comment
Мой вариант использования — поиск текста в заданной строке, пометка найденного текста и добавление всего этого в отформатированную строку (из файла strings.xml). до и после (как я показал в приведенном выше коде) я добавляю другие вещи (пока только строки). Как я могу это сделать? - person android developer; 09.07.2016
comment
Кажется, это не противоречит моему ответу. После форматирования это по-прежнему строка, всего несколько тегов html, которые рассматриваются как обычная строка. - person Harlan; 09.07.2016
comment
Не могли бы вы продемонстрировать? пример: строка в файле strings.xml — hello %s. вместо %s был бы мир, и я ищу или . Результат должен быть hello world, где только или будет выделено - person android developer; 09.07.2016
comment
измените строку на «hello w‹b›or‹/b›ld» в коде Java, я думаю, что это легко сделать. - person Harlan; 09.07.2016
comment
Я думаю, что вы написали неправильно, но я думаю, что это: изменить строку, которая будет вставлена, чтобы она была с HTML-тегами, а затем отформатировать, а затем использовать Html.fromHtml. - person android developer; 09.07.2016
comment
Извините, мой английский плохой, но я думаю, что вы поняли суть. - person Harlan; 09.07.2016
comment
Разве Html.fromHtml не менее эффективен, чем создание составных объектов самостоятельно? - person android developer; 09.07.2016
comment
Как насчет этого решения: github.com/george-steel/android-utils/blob/master/src/org/ ? - person android developer; 09.07.2016
comment
Я не думаю, что обработка синтаксиса формата с таким небольшим количеством кода надежна, потому что синтаксис очень сложен. - person Harlan; 09.07.2016
comment
Что такое em и почему вы не закрываете тег font? - person android developer; 09.07.2016
comment
Текст в теге em будет выделен курсивом. Извините, я забыл закрыть тег шрифта - person Harlan; 09.07.2016
comment
Как вы сделали подсветку текста с помощью тегов HTML? Кроме того, ввод должен быть строкой без каких-либо тегов. Только заполнители. текст, который заменит заполнитель, будет частично выделен внутри него. - person android developer; 09.07.2016