Android HtmlCompat.toHtml(Spanned) возвращает неправильно вложенные HTML-теги

#android #html #android-edittext #fromhtml

Вопрос:

У меня есть редактируемый текст (binding.text с использованием привязки представления), который содержит текст, стилизованный с интервалами стилей, т. Е. полужирным шрифтом и курсивом. Чтобы сохранить отформатированный текст, я использую HtmlCompat.toHtml(расширяемый) в Kotlin для преобразования его в HTML.

 var htmlString = HtmlCompat.toHtml(SpannableString(binding.text.text), HtmlCompat.FROM_HTML_MODE_LEGACY)
 

Однако возвращаемый HTML-код неправильно вложен, если текст выделен полужирным шрифтом и курсивом одновременно.

  • Привет, Мир: выходы <p dir="ltr><b><i>Hello world</b></i></p>

Как вы можете видеть, <b><i> </b></i> вместо этого применяются теги <b><i> </i></b> .


Если текст не отформатирован или выделен жирным шрифтом или курсивом, возвращается правильный HTML:

  • Привет, Мир: выходы <p dir="ltr>Hello world</p>
  • Привет, Мир: выходы <p dir="ltr><b>Hello world</b></p>

Я полагаю , что функция любит ставить <b> » и </b> «на первое место, а не <i> «и </i> «, но это приводит к странным результатам, как показано на рисунке. Итак, вопрос: как заставить функцию возвращать правильно отформатированный HTML?

Ответ №1:

Вы правы насчет заказа, хотя HTML-код все равно должен правильно отображаться в браузере. Код правонарушения находится в Html.java. Вот где происходят переводы для <b></b> и <i></i> :

 ...
for (int j = 0; j < style.length; j  ) {    
    ...
    if (style[j] instanceof StyleSpan) {
        int s = ((StyleSpan) style[j]).getStyle();
    
        if ((s amp; Typeface.BOLD) != 0) {
            out.append("<b>");
        }
        if ((s amp; Typeface.ITALIC) != 0) {
            out.append("<i>");
        }
    }

...
for (int j = style.length - 1; j >= 0; j--) {
    ,,,
    if (style[j] instanceof StyleSpan) {
        int s = ((StyleSpan) style[j]).getStyle();
    
        if ((s amp; Typeface.BOLD) != 0) {
            out.append("</b>");
        }
        if ((s amp; Typeface.ITALIC) != 0) {
            out.append("</i>");
        }
    }
 

style представляет собой массив пролетов. Этот код сканирует промежутки вперед, чтобы разместить открывающие теги, и назад, чтобы закрыть теги. Таким образом, похоже, что если ваши полужирные и курсивные интервалы являются разными интервалами, охватывающими один и тот же текст, то этот код создаст правильно вложенные теги.

Однако, если в одном интервале стилей указаны как курсив, так и полужирный шрифт, порядок тегов будет таким, как вы сообщаете <b><i></b></i> . Код, который выводит закрывающие теги, должен быть размещен <i> раньше b . Это похоже на ошибку, и об этом следует сообщить.

Я предполагаю, что у вас есть один стиль, который выделен жирным курсивом. Исправление состояло бы в том, чтобы разделить этот промежуток на два отдельных промежутка — выделенный жирным шрифтом и выделенный курсивом. Затем код должен работать так, как ожидалось.

Комментарии:

1. Да, именно это и произошло! Я использовал выделенный жирным курсивом промежуток, так как думал, что он чище, чем два отдельных промежутка, но теперь я знаю лучше. Большое спасибо за ваше руководство 🙂

2. @TongJingYen То, что ты сделал, должно быть в порядке, и это то, что я бы сделал. Это ошибка в Html.java код. Я собираюсь сообщить об этом и дать ссылку на этот пост.

3. @TongJingYen Вот отчет об ошибке .

4. Спасибо за отчет. Можно ли мне добавить скриншот в качестве комментария к нему?

5. @TongJingYen Я думаю, что это было бы нормально.