You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android TextView加载嵌套HTML列表(二级/三级项目符号)显示异常问题

Fixing Nested HTML List Display in Android TextView

Hey there! I’ve dealt with this exact nested bullet point issue in Android’s TextView before—it’s so annoying when sub-lists don’t render properly. Let’s walk through the most reliable fixes:

Why This Happens

Android’s native Html.fromHtml() (especially the legacy version) has terrible support for nested <ul>/<li> tags. It often ignores indentation and fails to display sub-bullets because the default Spanned text processing doesn’t handle nested list structures well.

Solution 1: Use AndroidX HtmlCompat (Basic Fix)

First, switch to AndroidX’s HtmlCompat library—it has better HTML parsing than the old system Html class. Here’s how to implement it:

import androidx.core.text.HtmlCompat

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val htmlContent = """
        <ul> 
            <li>Some bullet point text.</li> 
            <li>Another bullet point:</li> 
            <ul> 
                <li>A Sub Bullet point of the above.</li> 
                <ul> 
                    <li>A Sub sub bullet point.</li> 
                </ul> 
                <li>The second sub bullet point.</li> 
            </ul> 
        </ul>
    """.trimIndent()

    val textView = findViewById<TextView>(R.id.your_text_view_id)
    // Use FROM_HTML_MODE_COMPACT for better nested list support
    textView.text = HtmlCompat.fromHtml(htmlContent, HtmlCompat.FROM_HTML_MODE_COMPACT)
}

This will fix basic sub-bullet display, but you might still notice inconsistent indentation. For that, move to the next solution.

Solution 2: Custom TagHandler for Proper Indentation

To get clean, consistent indentation for nested lists, create a custom TagHandler to handle <ul> and <li> tags manually:

Step 1: Create the NestedListTagHandler Class

import android.text.Editable
import android.text.Html
import android.text.Spanned
import android.text.style.BulletSpan
import android.text.style.LeadingMarginSpan
import android.util.TypedValue
import android.content.res.Resources

class NestedListTagHandler : Html.TagHandler {
    private var indentLevel = 0
    private val density = Resources.getSystem().displayMetrics.density

    override fun handleTag(opening: Boolean, tag: String, output: Editable, xmlReader: Html.TagReader) {
        when (tag.lowercase()) {
            "ul" -> {
                if (opening) indentLevel++ else indentLevel--
            }
            "li" -> {
                if (opening) {
                    // Convert dp to px for consistent spacing across devices
                    val bulletGap = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10f, density).toInt()
                    val indentSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30f, density).toInt() * indentLevel

                    // Add indentation
                    output.setSpan(
                        LeadingMarginSpan.Standard(indentSize, indentSize),
                        output.length,
                        output.length,
                        Spanned.SPAN_MARK_MARK
                    )
                    // Add bullet point
                    output.setSpan(
                        BulletSpan(bulletGap),
                        output.length,
                        output.length,
                        Spanned.SPAN_MARK_MARK
                    )
                }
            }
        }
    }
}

Step 2: Use the Custom TagHandler in Your Activity

textView.text = HtmlCompat.fromHtml(
    htmlContent,
    HtmlCompat.FROM_HTML_MODE_COMPACT,
    null, // ImageGetter (leave null if no images)
    NestedListTagHandler()
)

This will properly indent each sub-list level and display bullet points for all nested items.

Solution 3: Fallback to WebView (For Complex HTML)

If you need full HTML/CSS support (like custom bullet styles or advanced formatting), replace the TextView with a WebView. It handles nested lists flawlessly out of the box:

import android.webkit.WebView
import android.graphics.Color

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val htmlContent = // Your nested list HTML here
    val webView = findViewById<WebView>(R.id.your_web_view_id)

    // Configure WebView to look like a TextView
    webView.setBackgroundColor(Color.TRANSPARENT)
    webView.settings.javaScriptEnabled = false
    webView.settings.setSupportZoom(false)
    
    // Load the HTML content
    webView.loadData(htmlContent, "text/html", "UTF-8")
}

Final Notes

  • Always use AndroidX HtmlCompat instead of the deprecated Html class for better compatibility.
  • The custom TagHandler is the best balance between native TextView performance and correct nested list rendering.
  • WebView is great for complex HTML, but it has higher memory overhead than TextView.

内容的提问来源于stack exchange,提问作者Jim Clermonts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:59:55