使用 Linkify.addLinks 与 Html.fromHtml 结合
Posted
技术标签:
【中文标题】使用 Linkify.addLinks 与 Html.fromHtml 结合【英文标题】:Using Linkify.addLinks combine with Html.fromHtml 【发布时间】:2013-01-10 09:06:24 【问题描述】:我有一个TextView
,通过调用它来获取它的数据集:
tv.setText(html.fromHtml(myText));
字符串myText
包含部分格式化的html 数据。例如,它可能有字体标签,但没有任何使用<a href=...>
标签格式化的 url 链接。我希望使用Linkify.addLinks(...)
来做到这一点,因为我的文本可能包含 Linkify 会为我适当转换的其他类型的链接。所以我把我的代码写成这样:
String myText = "<font color=\"red\">Red text</font> and Url: www.google.com";
tv.setText(Html.fromHtml(myText));
Linkify.addLinks(tv, Linkify.ALL);
tv.setMovementMethod(LinkMovementMethod.getInstance());
这不能正常工作。这意味着它会处理字体标签,但 Linkify 不会将 url 正确转换为 UrlSpan
。
或者,如果我在没有 Html.fromHtml(..) 的情况下调用 setText(),Linkify 可以工作,但是我会丢失所有从 html 字体标签格式化的文本。不知何故,它们似乎都有冲突,而我只能选择其中一个。
现在这是我不明白的有趣部分。如果我从 java 中删除 Linkify 代码并转到我的布局 xml 并将以下行放在那里,一切似乎都在工作(Linkify 和 fromHtml 最终都很好地结合在一起......不知何故)
<TextView
...
android:autoLink="all"
android:linksClickable="true"
...
/>
有人可以向我解释为什么这会让一切正常吗?
我查看了 TextView 的 setMovementMethod()
的源代码,它最终调用了:
setFocusable(true);
setClickable(true);
setLongClickable(true);
理论上,这应该可以使一切正常运行,并且与 xml 布局代码的行为相同。我尝试在java代码中在setText(Html.fromHtml(..))
之前切换调用Linkify.addLinks(..)
的顺序,但这并没有什么不同。
关于为什么在 java 中结合 Linkify.addLinks() 和 Html.fromHtml() 会导致这种行为的任何想法......但不会在 xml 布局中?
【问题讨论】:
@gmazzo 答案工作正常,应该被接受:***.com/a/17201376/2068732 【参考方案1】:这是因为 Html.fromHtml
和 Linkify.addLinks
在处理文本之前删除了之前的 span。
使用此代码使其工作:
public static Spannable linkifyHtml(String html, int linkifyMask)
Spanned text = Html.fromHtml(html);
URLSpan[] currentSpans = text.getSpans(0, text.length(), URLSpan.class);
SpannableString buffer = new SpannableString(text);
Linkify.addLinks(buffer, linkifyMask);
for (URLSpan span : currentSpans)
int end = text.getSpanEnd(span);
int start = text.getSpanStart(span);
buffer.setSpan(span, start, end, 0);
return buffer;
【讨论】:
别忘了加textView.setMovementMethod(LinkMovementMethod.getInstance());
如果您有一些<a href="oneLink">otherLink</a>
,它将导致指向otherLink
的可点击链接。您可以在将新跨度添加到缓冲区以解决此问题并获得指向oneLink
的链接之前删除[start, end]
中的所有URLSpan
。
我发现错误...需要创建新的 URLSpan。发布了新答案【参考方案2】:
你可以试试这个:
首先将文本设置到您的 TextView 中。
tv.setText(myText);
使用 Linkify 转换链接
Linkify.addLinks(tv, Linkify.ALL);
最后用 Html.fromHtml 替换文本,但使用 EditText 中的链接文本。
tv.setText(Html.fromHtml(tv.getText().toString()));
【讨论】:
我认为这永远行不通。对toString()
的调用将只返回一个没有任何跨度的纯字符串。您必须手动累积跨度,然后调用 setMovementMethod()
,就像在 gmazzo 的回答中一样【参考方案3】:
100% 有效的解决方案 (kotlin)。
在 Linkify 之前为商店 HtmlLink 创建类
class HtmlLink(val urlSpan: URLSpan, val spanStart: Int, val spanEnd: Int)
创建跨区 html(两种格式都用于测试)
val spanned = Html.fromHtml("https://google.com" +
"<br><a href=\"https://google.com\">Google</a>")
存储html
val htmlLinks = ArrayList<HtmlLink>()
spanned.getSpans(0, spanned.length, URLSpan::class.java).forEach urlSpan ->
htmlLinks.add(HtmlLink(urlSpan,
spanned.getSpanStart(urlSpan),
spanned.getSpanEnd(urlSpan)))
创建spannable builder并链接它
val builder = SpannableString(spanned)
Linkify.addLinks(builder, Linkify.WEB_URLS)
恢复跨度。
htmlLinks.forEach htmlLink ->
builder.setSpan(URLSpan(htmlLink.urlSpan.url), htmlLink.spanStart, htmlLink.spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
设置最终文本
scrollContent.text = builder
【讨论】:
以上是关于使用 Linkify.addLinks 与 Html.fromHtml 结合的主要内容,如果未能解决你的问题,请参考以下文章
Android Linkify.addLinks() 适用于一个 textview 而不是另一个
使用正则表达式突出显示文本中的链接(Linkify vs Patterns)
Android Linkify 电话号码 - 如何指定要链接的号码和不链接的号码