38

我有这个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));

这导致:

生成的屏幕截图

“受让人...”是另一个TextView
TextView的是灰色背景的。非常浅的灰色可以清楚地看到它的边界。左边的深灰色条是背景的一部分,所以它也是TextView

我们可以清楚地看到 8dp 方形填充。但是,底部的空白空间是什么?这是某种填充,但我没有在 XML 或代码中设置它!

如果有人问,我需要HTML 支持,因为与上面显示的屏幕截图不同,内容可能包含一些 HTML 内容(<pre><i><b>等)。

4

8 回答 8

69

您看到的额外“填充”实际上只是一个换行符,然后是另一个换行符:

在此处输入图像描述

当您深入研究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 返回一个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);

瞧,之前和之后:

在此处输入图像描述

于 2013-05-25T01:21:33.917 回答
18

您也可以使用以下代码

 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;
}
于 2014-07-31T12:10:43.467 回答
8

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());
于 2016-12-02T13:40:38.800 回答
1

试试这个,去掉<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));

希望它有效。

于 2013-05-16T11:10:20.503 回答
1

处理 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);
    }
}
于 2019-01-24T14:22:26.960 回答
1

根据 Android 文档, Html.fromHtml() 使用 FROM_HTML_MODE_LEGACY 将 HTML 转换为文本。但是 FROM_HTML_MODE_LEGACY 在两者之间添加了两个换行符。

从 Android N 开始,FROM_HTML_MODE_COMPACT 默认只使用一个换行符。

/**
     * Flags for {@link #fromHtml(String, int, ImageGetter, TagHandler)}: Separate block-level
     * elements with blank lines (two newline characters) in between. This is the legacy behavior
     * prior to N.
     */
    public static final int FROM_HTML_MODE_LEGACY = 0x00000000;

    /**
     * Flags for {@link #fromHtml(String, int, ImageGetter, TagHandler)}: Separate block-level
     * elements with line breaks (single newline character) in between. This inverts the
     * {@link Spanned} to HTML string conversion done with the option
     * {@link #TO_HTML_PARAGRAPH_LINES_INDIVIDUAL}.
     */
    public static final int FROM_HTML_MODE_COMPACT =
            FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH
            | FROM_HTML_SEPARATOR_LINE_BREAK_HEADING
            | FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM
            | FROM_HTML_SEPARATOR_LINE_BREAK_LIST
            | FROM_HTML_SEPARATOR_LINE_BREAK_DIV
            | FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE;

因此,为了将 HTML 转换为纯文本,我们可以使用,

HtmlCompat.fromHtml(htmlString, HtmlCompat.FROM_HTML_MODE_COMPACT);
于 2020-09-23T05:44:56.647 回答
0

TextView 周围的布局是什么?我记得有些布局忽略了组件的高度偏好,只是让它适合。

于 2013-05-16T11:00:40.010 回答
0

https://stackoverflow.com/a/16745540/2761728显示 Android 将\n在您的 html 标签末尾添加额外内容。答案显示了一种\n在内容末尾修剪不需要的内容的方法,但它不会\n为您删除 Android 插入的每个标签之间的内容。

就我而言,我有这个 html 内容:

<p>This is the first paragraph.</p><p>And this is second paragraph.</p>

之后Html.fromHtml,文本将变为

This is the first paragraph. 


And this is second paragraph. 


我尝试了一些方法,发现\n可以通过提供的标志来避免Html。我将代码trim与这个解决方案结合起来:

trimLastBreak(HtmlCompat.fromHtml(htmlContent, FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH))

结果是完美的:

This is the first paragraph.
And this is second paragraph.
于 2020-05-21T02:33:12.447 回答