Дополнительное дополнение в TextView с содержимым HTML
У меня есть TextView
:
<TextView
android:id="@+id/issue_journal_item_notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/issue_journal_item_details"
android:layout_below="@+id/issue_journal_item_details"
android:background="@drawable/journal_item_notes_background"
android:padding="8dp"
android:text="issue_journal_item_notes"
android:textIsSelectable="true" />
Я заполняю это:
String html = "<p>Hi,<br/>Do you think you could get a logcat during the crash? That seems really strange, especially the fact that it makes Android reboot.<br/>You can get the SDK here: http://developer.android.com/sdk/index.html<br/>(needed for logcat)</p>";
theTextView.setText(Html.fromHtml(html));
Это приводит к:
![Resulting screenshot]()
"Assignee..." - это еще один TextView
.
Мой TextView
- тот, у кого серый фон. Его границы отчетливо видны с очень светло-серым. Левая темная серая полоса слева является частью фона, поэтому она также TextView
Мы можем ясно видеть квадратное заполнение 8dp. Однако какое пустое пространство внизу? Это своего рода дополнение, но я не использовал это в XML и кодексе!
Если кто-то спросит, мне нужна поддержка HTML, потому что в отличие от приведенного выше скриншота, содержимое может содержать некоторый HTML-контент (<pre>
, <i>
, <b>
и т.д.).
Ответы
Ответ 1
Дополнительное "дополнение", которое вы видите, на самом деле представляет собой просто разрыв строки, за которым следует другой разрыв строки:
![enter image description here]()
Когда вы погружаетесь в реализацию Html.fromHtml(...)
, вы столкнетесь с следующим методом, который обрабатывает теги абзаца:
private static void handleP(SpannableStringBuilder text) {
int len = text.length();
if (len >= 1 && text.charAt(len - 1) == '\n') {
if (len >= 2 && text.charAt(len - 2) == '\n') {
return;
}
text.append("\n");
return;
}
if (len != 0) {
text.append("\n\n");
}
}
Выше фрагмент был взят из источника Android 4.2.2. Логика довольно проста и в основном гарантирует, что каждый абзац абзаца заканчивается на \n\n
, чтобы получить визуальный зазор между двумя блоками элементов. Это означает, что структура не будет учитывать, весь ли текст Html состоит только из одного абзаца (вашего случая) или нескольких последовательных парагапов - в конце преобразованного абзаца всегда будут два разрыва строки.
Если вы знаете, что вы всегда имеете дело с одним абзацем, самым простым решением является удаление этого абзаца обертывания перед его подачей на Html.fromHtml(...)
. Это в значительной степени то, что было предложено в одном из других ответов.
Теперь, поскольку вы упомянули, что это не вариант, альтернативой будет "обрезать" результат Html.fromHtml(...)
, удалив любые завершающие пробелы. Android возвращает a Spanned
(обычно это объект SpannableStringBuilder
), который, к сожалению, не имеет встроенного метода trim()
. Это не слишком сложно, чтобы придумать свои собственные, или взять одну из нескольких доступных там реализаций.
Базовая реализация для метода trim()
должна выглядеть примерно так:
public static CharSequence trim(CharSequence s, int start, int end) {
while (start < end && Character.isWhitespace(s.charAt(start))) {
start++;
}
while (end > start && Character.isWhitespace(s.charAt(end - 1))) {
end--;
}
return s.subSequence(start, end);
}
Чтобы использовать его, измените исходный код на:
String html = "<p>Hi,<br/>Do you think you could get a logcat during the crash? That seems really strange, especially the fact that it makes Android reboot.<br/>You can get the SDK here: http://developer.android.com/sdk/index.html<br/>(needed for logcat)</p>";
CharSequence trimmed = trim(Html.fromHtml(html));
theTextView.setText(trimmed);
И вуаля, до и после:
![enter image description here]()
Ответ 2
Вы также можете использовать ниже код
myTextView.setText(noTrailingwhiteLines(html));
private CharSequence noTrailingwhiteLines(CharSequence text) {
while (text.charAt(text.length() - 1) == '\n') {
text = text.subSequence(0, text.length() - 1);
}
return text;
}
Ответ 3
Html.fromHtml(html)
возвращает Spannable
, поэтому вы можете преобразовать его в строку, вызвав toString()
, затем trim
строку, затем установите ее на textview
String html = "<p>Hi,<br/>Do you think you could get a logcat during the crash? That seems really strange, especially the fact that it makes Android reboot.<br/>You can get the SDK here: http://developer.android.com/sdk/index.html<br/>(needed for logcat)</p>";
theTextView.setText(Html.fromHtml(html).toString().trim());
Ответ 4
Каков внешний вид вашего TextView? Я помню, что некоторые макеты игнорируют предпочтение высоты вашего компонента и просто делают его пригодным.
Ответ 5
Попробуйте это, удалив тег <p>
.
String html = "Hi,<br/>Do you think you could get a logcat during the crash? That seems really strange, especially the fact that it makes Android reboot.<br/>You can get the SDK here: http://developer.android.com/sdk/index.html<br/>(needed for logcat)";
theTextView.setText(Html.fromHtml(html));
Надеюсь, что это сработает.
Ответ 6
Обработка тегов HTML приводит к добавлению новых строк \n
, а иногда и нескольких \n
следующих друг за другом. Результатом будет строка с несколькими символами новой строки между текстом (особенно если строка HTML содержит тег <br/>
).
Следующий метод удаляет начальные и конечные символы новой строки, которые являются результатом <br/> tag.
Кроме того, сокращается несколько новых строк между текстом (API> 24).
/**
*
* @param htmlString
* @return Spanned represents the html string removed leading and trailing newlines. Also, reduced newlines resulted from processing HTML tags (for API >24)
*/
public static Spanned processHtmlString(String htmlString){
// remove leading <br/>
while (htmlString.startsWith("<br/>")){
htmlString = htmlString.replaceFirst("<br/>", "");
}
// remove trailing <br/>
while (htmlString.endsWith("<br/>")){
htmlString = htmlString.replaceAll("<br/>$", "");
}
// reduce multiple \n in the processed HTML string
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(htmlString, FROM_HTML_MODE_COMPACT);
}else{
return Html.fromHtml(htmlString);
}
}