一、   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();
        spannableStringBuilder.append(urlSpan);
        textView.setText(spannableStringBuilder);

未设置autoLink属性,超链接正常展示。但突然有一天发现TextView中有一个url纯文本未展示位超链接。


最近项目中遇到一个问题,卡了半天,和大家分享下。

    我们的android应用需要在TextView中展示超链接(与3ms写博客中的超链接功能一样),这个超链接也是用户设置的包括超链接的显示名称和url。富文本格式为[url=www.baidu.com]百度[/url]

-java代码
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);
    上面的TextView是用来展示帖子的全部内容的,正常情况下超链接都显示OK。但若帖子内容中用户直接粘贴了链接的url而没有使用[url]富文本格式,此时该url就不能自动识别、和展示位超链接了。

    于是在网上搜索了下,发现要实现自动识别url很简单,只要设置TextView的autoLink属性为"web"即可。于是乎我设置了android:autoLink="web",发现url可以自动识别为超链接,但突然使用UrlSpan设置的超链接没了,这么诡异。。。。

    查看了源码才发现,先看看setText()方法实现

-java代码
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     }

    上面可以看到mAutoLinkMask属性(可以再xml中设置android:autoLink="web"或使用TextView.setAutoLink()方法设置)不为空时,使用Linkify.addLinks(s2, mAutoLinkMask)将TextView文本中的url自动识别并转换为UrlSpan.

-java代码
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 links = 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                 nullnull);
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     }

        上面是Linkify.addLinks()方法源码,其中做了三件事情:

1.删除text文本中原有的Spanable

2.使用gatherLinks()是使用正则表达式匹配各种类型的url

3.最终使用applyLink()将2中匹配到的url生成UrlSpan。

下面是Linkify.applyLink()源码

-java代码
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 }
    可以看出 Linkify.applyLink()方法其实就是将前面使用正则表达式匹配出来的各种类型( WEB_URLS、 EMAIL_ADDRESSES、 MAP_ADDRESSES等 )超链接字符串来构造UrlSpan。

    这也就解释了为何我设置了autoLink属性,但我自行构造的UrlSpan都不展示为超链接的原因了,被删除了。

    再看看TextView::append()方法

-java代码
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     }

    可以看出,首次调用append()方法首先会把TextView的BufferType设置为BufferType.EDITABLE。然后追加文本,并且追加文本时不会进行Linkify.addLinks()操作,也即append()追加的文本不会自动识别url。


我最终实现超链接方法如下:

-java代码
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 }

即自定调用Linkify.addLink()方法转化url字符串为UrlSpan。

问题2:自定义超链接字体颜色

方法1:继承URLSpan类并复写updateDrawState()方法

@Overridepublic void updateDrawState(TextPaint ds) {ds.setColor(Color.rgb(40, 192, 198));//#28C0C6ds.setUnderlineText(true);}
当然也可以复写URLSpan::onClick()自定义超链接的点击事件处理。


方法2:设置TextView的android:textAppearance属性

android:textAppearance="@style/CustomTextAppearance"

或textView.setTextAppearance(mContext, R.style.CustomTextAppearance);



更多相关文章

  1. Android VideoView设置静音,Android 设置VideoView静音,Android
  2. ListView去掉分割线的几种方法
  3. SDK Platform Tools component is missing! Please use the SDK
  4. Android Market google play store帐号注册方法流程 及发布应用
  5. textview设置文本每行的行间距
  6. Android 实现全屏显示的几种方法整理
  7. Android中TextView中内容不换行的解决方法
  8. Android模拟、实现、触发系统按键事件的方法
  9. android 2.2+ 完全退出程序的方法

随机推荐

  1. 传智播客Android核心基础课程视频教程(收
  2. android studio编译错误 之 Cause: com/a
  3. Android 创建菜单栏
  4. relative相关属性
  5. android调用系统发短信界面功能
  6. ubuntu共享文件夹设置
  7. Drawable Mutations(Android(安卓)Drawab
  8. 【建议收藏】2020年中高级Android大厂面
  9. android学习资料
  10. Android 自动滚动的GridView