一、 Android的TextView中展示超链接有三种方式:
1. 使用Html.fromHtml(source)方法将html的如下文本转换为android支持的Spannable
Spanned spanned = Html.fromHtml("
textView.append(spanned);
2. 在java代码中使用UrlSpan
SpannableString ss = new SpannableString("谷歌");
ss.setSpan(newURLSpan("http://www.google.com\"), 0, 2,Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(ss);
3. 直接将带有url的字符串设置到TextView中
textView.setText("http://www.google.com\");前提是已设置TextView的autoLink属性
或textView.append(Linkify.addLinks("http://www.google.com\",Linkify.WEB_URLS));无需设置autoLink属性
二、 设置TextView的autoLink属性的方法:
android:id="@+id/testweb" android:layout_width="fill_parent" android:layout_height="wrap_content" android:autoLink="web" //是将文本的web网址解释成超链接,也可以使用TextView.setAutoLinkMask(mask)方法设置该属性 android:text="@string/link_text_auto"/> 三、 我在开发过程中遇到的问题 类似微博、贴吧的android客户端开发时,对于超链接富文本在android端我直接使用上面的方法2(UrlSpan)展示所有帖子的超链接。 SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(); 未设置autoLink属性,超链接正常展示。但突然有一天发现TextView中有一个url纯文本未展示位超链接。 最近项目中遇到一个问题,卡了半天,和大家分享下。 我们的android应用需要在TextView中展示超链接(与3ms写博客中的超链接功能一样),这个超链接也是用户设置的包括超链接的显示名称和url。富文本格式为[url=www.baidu.com]百度[/url] 于是在网上搜索了下,发现要实现自动识别url很简单,只要设置TextView的autoLink属性为"web"即可。于是乎我设置了android:autoLink="web",发现url可以自动识别为超链接,但突然使用UrlSpan设置的超链接没了,这么诡异。。。。 查看了源码才发现,先看看setText()方法实现 上面可以看到mAutoLinkMask属性(可以再xml中设置android:autoLink="web"或使用TextView.setAutoLink()方法设置)不为空时,使用Linkify.addLinks(s2, mAutoLinkMask)将TextView文本中的url自动识别并转换为UrlSpan. 上面是Linkify.addLinks()方法源码,其中做了三件事情: 1.删除text文本中原有的Spanable 2.使用gatherLinks()是使用正则表达式匹配各种类型的url 3.最终使用applyLink()将2中匹配到的url生成UrlSpan。 下面是Linkify.applyLink()源码 这也就解释了为何我设置了autoLink属性,但我自行构造的UrlSpan都不展示为超链接的原因了,被删除了。 再看看TextView::append()方法 可以看出,首次调用append()方法首先会把TextView的BufferType设置为BufferType.EDITABLE。然后追加文本,并且追加文本时不会进行Linkify.addLinks()操作,也即append()追加的文本不会自动识别url。 我最终实现超链接方法如下: 即自定调用Linkify.addLink()方法转化url字符串为UrlSpan。 问题2:自定义超链接字体颜色 方法1:继承URLSpan类并复写updateDrawState()方法 方法2:设置TextView的android:textAppearance属性 android:textAppearance="@style/CustomTextAppearance" 或textView.setTextAppearance(mContext, R.style.CustomTextAppearance);
spannableStringBuilder.append(urlSpan);
textView.setText(spannableStringBuilder);
1
SpannableStringBuilder sb =
new
SpannableStringBuilder();
2
URLSpan span =
new
URLSpan(url);
3
SpannableString ss =
new
SpannableString(value);
4
ss.setSpan(span,
0
, value.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
5
sb.append(ss);
6
...
//可能有很多url超链接,故使用SpannableStringBuilder(它不仅仅包括urlSpan还包括纯文本内容数据)
7
textView.setText(sb);
01
private
void
setText(CharSequence text, BufferType type,
boolean
notifyBefore,
int
oldlen) {
02
...
03
if
(mAutoLinkMask !=
0
) {
04
Spannable s2;
05
06
if
(type == BufferType.EDITABLE || text
instanceof
Spannable) {
07
s2 = (Spannable) text;
08
}
else
{
09
s2 = mSpannableFactory.newSpannable(text);
10
}
11
12
if
(Linkify.addLinks(s2, mAutoLinkMask)) {
13
text = s2;
14
type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE :BufferType.SPANNABLE;
15
16
/*
17
* We must go ahead and set the text before changing the
18
* movement method, because setMovementMethod() may call
19
* setText() again to try to upgrade the buffer type.
20
*/
21
mText = text;
22
23
// Do not change the movement method for text that support text selection as it
24
// would prevent an arbitrary cursor displacement.
25
if
(mLinksClickable && !textCanBeSelected()) {
26
setMovementMethod(LinkMovementMethod.getInstance());
27
}
28
}
29
}
30
...
31
}
01
/**
02
* Scans the text of the provided Spannable and turns all occurrences
03
* of the link types indicated in the mask into clickable links.
04
* If the mask is nonzero, it also removes any existing URLSpans
05
* attached to the Spannable, to avoid problems if you call it
06
* repeatedly on the same text.
07
*/
08
public
static
final
boolean
addLinks(Spannable text,
int
mask) {
09
if
(mask ==
0
) {
10
return
false
;
11
}
12
13
URLSpan[] old = text.getSpans(
0
, text.length(), URLSpan.
class
);
14
15
for
(
int
i = old.length -
1
; i >=
0
; i--) {
16
text.removeSpan(old[i]);
17
}
18
19
ArrayList
new
ArrayList
20
21
if
((mask & WEB_URLS) !=
0
) {
22
gatherLinks(links, text, Patterns.WEB_URL,
23
new
String[] {
"http://"
,
"https://"
,
"rtsp://"
},
24
sUrlMatchFilter,
null
);
25
}
26
27
if
((mask & EMAIL_ADDRESSES) !=
0
) {
28
gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
29
new
String[] {
"mailto:"
},
30
null
,
null
);
31
}
32
33
if
((mask & PHONE_NUMBERS) !=
0
) {
34
gatherLinks(links, text, Patterns.PHONE,
35
new
String[] {
"tel:"
},
36
sPhoneNumberMatchFilter, sPhoneNumberTransformFilter);
37
}
38
39
if
((mask & MAP_ADDRESSES) !=
0
) {
40
gatherMapLinks(links, text);
41
}
42
43
pruneOverlaps(links);
44
45
if
(links.size() ==
0
) {
46
return
false
;
47
}
48
49
for
(LinkSpec link: links) {
50
applyLink(link.url, link.start, link.end, text);
51
}
52
53
return
true
;
54
}
1
private
static
final
void
applyLink(String url,
int
start,
int
end, Spannable text) {
2
URLSpan span =
new
URLSpan(url);
3
4
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
5
}
01
/**
02
* Convenience method: Append the specified text slice to the TextView's
03
* display buffer, upgrading it to BufferType.EDITABLE if it was
04
* not already editable.
05
*/
06
public
void
append(CharSequence text,
int
start,
int
end) {
07
if
(!(mText
instanceof
Editable)) {
08
setText(mText, BufferType.EDITABLE);
09
}
10
11
((Editable) mText).append(text, start, end);
12
}
01
while
(
/*循环条件*/
) {
02
if
(
/*富文本超链接*/
) {
03
...
04
if
(!TextUtils.isEmpty(url)) {
05
URLSpan span =
new
URLSpan(url);
06
SpannableString ss =
new
SpannableString(value);
07
ss.setSpan(span,
0
, value.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
08
textView.append(ss);
09
}
else
if
(
/*非图片附件*/
) {
10
...
11
URLSpan span =
new
URLSpan(attachmentUrl);
12
SpannableString ss =
new
SpannableString(attachmentName);
13
ss.setSpan(span,
0
, attachmentName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
14
textView.append(ss);
15
}
else
{
16
...
17
SpannableString spannableString =
new
SpannableString(textElement.getValue());
18
Linkify.addLinks(spannableString, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
19
textView.append(spannableString);
20
}
21
}
当然也可以复写URLSpan::onClick()自定义超链接的点击事件处理。
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.rgb(40, 192, 198));//#28C0C6
ds.setUnderlineText(true);
}