之前在『Android 改变 TextView 内局部样式』中介绍过利用 HTML 标签来设置样式,使用时你可能会遇到超链接跳转的需求,很容易你就能想到给 HTML 字符串添加 <a>
标签:
class MainActivity : AppCompatActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val content = Html.fromHtml(
"这是一个超链接:<a href='https://google.com'>Google</a>",
Html.FROM_HTML_MODE_LEGACY
)
binding.textView.text = content
}
}
TextView
确实出现了超链接的显示效果,但是却不能够响应点击。

我们还需要对其做进一步处理。这里同样用到了『Android 改变 TextView 内局部样式』中介绍的另一种方式,也就是 SpannableString
,代码如下:
class MainActivity : AppCompatActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val content = Html.fromHtml(
"这是一个超链接:<a href='https://google.com'>Google</a>",
Html.FROM_HTML_MODE_LEGACY
)
binding.textView.text = content
handleHtmlClick(binding.textView)
}
private fun handleHtmlClick(textView: TextView) {
textView.movementMethod = LinkMovementMethod.getInstance()
val text = textView.text
if (text is Spannable) {
val end = text.length
val spans = text.getSpans(0, end, URLSpan::class.java)
val sb = SpannableStringBuilder(text)
sb.clearSpans()
for (span in spans) {
sb.setSpan(
URLSpan(span.url),
text.getSpanStart(span),
text.getSpanEnd(span),
Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
textView.text = sb
}
}
}
这里通过 Spanned.getSpans()
方法提取到可点击的 URLSpan
,并重新构造 URLSpan
再添加到 SpannableString
中即可。URLSpan
是 ClickableSpan
的实现,当点击其中设置了 Span 的文本时,URLSpan
将尝试通过启动带有 Intent.ACTION_VIEW
的 Activity
来打开 URL。
上面代码的效果就是跳转到浏览器打开超链接。

如果希望接管点击后的逻辑,我们可以自行实现 ClickableSpan
:
class MainActivity : AppCompatActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val content = Html.fromHtml(
"这是一个超链接:<a href='https://google.com'>Google</a>",
Html.FROM_HTML_MODE_LEGACY
)
binding.textView.text = content
handleHtmlClick(binding.textView)
}
private fun handleHtmlClick(textView: TextView) {
textView.movementMethod = LinkMovementMethod.getInstance()
val text = textView.text
if (text is Spannable) {
val end = text.length
val spans = text.getSpans(0, end, URLSpan::class.java)
val sb = SpannableStringBuilder(text)
sb.clearSpans()
for (span in spans) {
sb.setSpan(
HypertextSpan(this, span.url),
text.getSpanStart(span),
text.getSpanEnd(span),
Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
textView.text = sb
}
}
}
class HypertextSpan(private val context: Context, private val url: String) : ClickableSpan() {
override fun onClick(widget: View) {
// 处理点击逻辑
}
}
我们构造一个 HypertextSpan
来接管点击逻辑,只需将上一步的 URLSpan
替换即可,构造方法中传入 Context
和 URL 可以方便我们处理判断及跳转。
比如在应用内打开网页:
