一、需求
1、在TextView中识别url;
2、能识别出非http://|https://|ftp://等协议开头的非标准url
3、对url设置颜色、下划线、点击等等
二、方案
LinkedList<String> mStringList = new LinkedList<String>(); LinkedList<UrlInfo> mUrlInfos = new LinkedList<UrlInfo>(); private String pattern = "((http|ftp|https)://)(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?|(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?"; Pattern r = Pattern.compile(pattern); Matcher m; int flag= Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; class UrlInfo { public int start; public int end; } public SpannableStringBuilderForAllvers identifyUrl(CharSequence text) { mStringList.clear(); mUrlInfos.clear(); CharSequence contextText; CharSequence clickText; text = text == null ? "" : text; //以下用于拼接本来存在的spanText SpannableStringBuilderForAllvers span = new SpannableStringBuilderForAllvers(text); ClickableSpan[] clickableSpans = span.getSpans(0, text.length(), ClickableSpan.class); if (clickableSpans.length > 0) { int start=0; int end=0; for (int i=0;i<clickableSpans.length;i++){ start=span.getSpanStart(clickableSpans[0]); end=span.getSpanEnd(clickableSpans[i]); } //可点击文本后面的内容页 contextText = text.subSequence(end, text.length()); //可点击文本 clickText = text.subSequence(start, end); } else { contextText = text; clickText = null; } m = r.matcher(contextText); //匹配成功 while (m.find()) { //得到网址数 UrlInfo info = new UrlInfo(); info.start = m.start(); info.end = m.end(); mStringList.add(m.group()); mUrlInfos.add(info); } return joinText(clickText, contextText); } /** 拼接文本 */ private SpannableStringBuilderForAllvers joinText(CharSequence clickSpanText, CharSequence contentText) { SpannableStringBuilderForAllvers spanBuilder; if (clickSpanText != null) { spanBuilder = new SpannableStringBuilderForAllvers(clickSpanText); } else { spanBuilder = new SpannableStringBuilderForAllvers(); } if (mStringList.size() > 0) { //只有一个网址 if (mStringList.size() == 1) { String preStr = contentText.toString().substring(0, mUrlInfos.get(0).start); spanBuilder.append(preStr); String url = mStringList.get(0); int start = spanBuilder.length(); spanBuilder.append(url, new UnderlineSpan(), flag); int end = spanBuilder.length(); if (start >= 0 && end > 0 && end > start) { spanBuilder.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, flag); } String nextStr = contentText.toString().substring(mUrlInfos.get(0).end); spanBuilder.append(nextStr); } else { //有多个网址 for (int i = 0; i < mStringList.size(); i++) { if (i == 0) { //拼接第1个span的前面文本 String headStr = contentText.toString().substring(0, mUrlInfos.get(0).start); spanBuilder.append(headStr); } if (i == mStringList.size() - 1) { //拼接最后一个span的后面的文本 int start = spanBuilder.length(); spanBuilder.append(mStringList.get(i), new UnderlineSpan(), flag); int end = spanBuilder.length(); if (start >= 0 && end > 0 && end > start) { spanBuilder.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, flag); } String footStr = contentText.toString().substring(mUrlInfos.get(i).end); spanBuilder.append(footStr); } if (i != mStringList.size() - 1) { //拼接两两span之间的文本 int start = spanBuilder.length(); spanBuilder.append(mStringList.get(i), new UnderlineSpan(), flag); int end = spanBuilder.length(); if (start >= 0 && end > 0 && end > start) { spanBuilder.setSpan(new ForegroundColorSpan(Color.BLUE), start, end, flag); } String betweenStr = contentText.toString() .substring(mUrlInfos.get(i).end, mUrlInfos.get(i + 1).start); spanBuilder.append(betweenStr); } } } } else { spanBuilder.append(contentText); } return spanBuilder; }
public class SpannableStringBuilderForAllvers extends SpannableStringBuilder{ public SpannableStringBuilderForAllvers() { super(""); } public SpannableStringBuilderForAllvers(CharSequence text) { super(text, 0, text.length()); } public SpannableStringBuilderForAllvers(CharSequence text, int start, int end){ super(text,start,end); } @Override public SpannableStringBuilder append(CharSequence text) { if (text == null) { return this; } int length = length(); return (SpannableStringBuilderForAllvers)replace(length, length, text, 0, text.length()); } /**该方法在原API里面只支持API21或者以上,这里适应低版本*/ public SpannableStringBuilderForAllvers append(CharSequence text, Object what, int flags) { if (text == null) { return this; } int start = length(); append(text); setSpan(what, start, length(), flags); return this; } }