Android开源中国客户端学习(4) 自定义LinkView处理超链接

 OSC中超链接有 新闻超链接,@好友超链接,话题超链接等等.

在讲OSC的处理之前,我先大概说下我以前做新浪微博时的处理,看了OSC的处理后,我发现这种处理很不错。。

  首先,先说下我之前处理超链接的方法

public static SpannableString Autolink(String txt, final Context con) {
		SpannableString spannableString = new SpannableString(txt);
		Pattern pattern = Pattern.compile("@([a-zA-Z0-9_\\-\\u4e00-\\u9fa5]+)|"
				+ "#([^\\#|.]+)#" + "|http://t\\.cn/\\w|" + "\\[(\\S+?)\\]");
		Matcher matcher = pattern.matcher(txt);
		while (matcher.find()) {
			final String group = matcher.group();
			if (group.startsWith("@")) {
				spannableString.setSpan(new ClickableSpan() {
					@Override
					public void onClick(View widget) {
						Toast.makeText(con, group, Toast.LENGTH_SHORT).show();
						Intent in = new Intent(con, HomeActivity.class);
						in.putExtra("username", group.substring(1));
						con.startActivity(in);
					}
				}, matcher.start(), matcher.end(),
						Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
				spannableString.setSpan(new ForegroundColorSpan(0xff0077ff),
						matcher.start(), matcher.end(),
						Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			} else if (group.startsWith("#")) {
				spannableString.setSpan(new ForegroundColorSpan(0xff0077ff),
						matcher.start(), matcher.end(),
						Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			} else if (group.startsWith("#")) {
			} else if (group.startsWith("[")) {
				Bitmap b = MyApplication.getInstence().getEmotion(group);
				spannableString.setSpan(new ImageSpan(con,b), matcher.start(),
						matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			} else if (group.startsWith("http://")) {

			}

		}
		return spannableString;
	}
首先定义一个正则表达式,根据开头的字符进行不同的处理 ,接下来如何使用呢?

holder.tvItemContent.setText(TextUtil.Autolink((String) getData(position, "text"), mContext));
很简单,但是,我们会发现一个问题,那就是点击listview的item只会响应那个超链接其他所有都不能响应了,当时使用了其他方法处理,下面OSC用了另外一种方法,非常不错。

下面主要说说OSC的处理,OSC是通过重写一个TextView实现的

public class LinkView extends TextView {
	private OnLinkClickListener mLinkClickListener = new LinkView.OnLinkClickListener() {
		@Override
		public void onLinkClick() {

		}
	};

	public LinkView(Context context) {
		super(context);
	}

	public LinkView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public LinkView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public OnLinkClickListener getLinkClickListener() {
		return mLinkClickListener;
	}

	public void setLinkClickListener(OnLinkClickListener linkClickListener) {
		this.mLinkClickListener = linkClickListener;
	}

	public void setLinkText(String linktxt) {
		Spanned span = Html.fromHtml(linktxt);
		setText(span);
		setMovementMethod(LinkMovementMethod.getInstance());
		parseLinkText(span);
	}

	public void parseLinkText(Spanned spanhtml) {
		CharSequence text = getText();
		if (text instanceof Spannable) {
			int end = text.length();
			Spannable sp = (Spannable) getText();
			URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);

			URLSpan[] htmlurls = spanhtml != null ? spanhtml.getSpans(0, end,
					URLSpan.class) : new URLSpan[] {};

			if (urls.length == 0 && htmlurls.length == 0)
				return;

			SpannableStringBuilder style = new SpannableStringBuilder(text);
			for (URLSpan url : urls) {
				if (!isNormalUrl(url)) {
					style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置
					NoLinkSpan span = new NoLinkSpan(url.getURL());
					style.setSpan(span, sp.getSpanStart(url),
							sp.getSpanEnd(url),
							Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
					continue;
				}
				style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置
				MyURLSpan myURLSpan = new MyURLSpan(url.getURL());
				style.setSpan(myURLSpan, sp.getSpanStart(url),
						sp.getSpanEnd(url), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			for (URLSpan url : htmlurls) {
				style.removeSpan(url);// 只需要移除之前的URL样式,再重新设置
				MyURLSpan myURLSpan = new MyURLSpan(url.getURL());
				style.setSpan(myURLSpan, spanhtml.getSpanStart(url),
						spanhtml.getSpanEnd(url),
						Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			setText(style);
		}
	}

	public void parseLinkText() {
		parseLinkText(null);
	}

	public class MyURLSpan extends ClickableSpan {
		private String mUrl;

		public MyURLSpan(String url) {
			mUrl = url;
		}

		@Override
		public void onClick(View widget) {
			mLinkClickListener.onLinkClick();
			URLs urls = URLs.parseURL(mUrl);
			if (urls != null) {
				UIHelper.showLinkRedirect(widget.getContext(),
						urls.getObjType(), urls.getObjId(), urls.getObjKey());
			} else {
				UIHelper.openBrowser(widget.getContext(), mUrl);
			}
		}
	}

	/**
	 * 无响应的ClickableSpan
	 * 
	 * @author yeguozhong@yeah.net
	 * 
	 */
	public class NoLinkSpan extends ClickableSpan {
		private String text;

		public NoLinkSpan(String text) {
			super();
			this.text = text;
		}

		@Override
		public void updateDrawState(TextPaint ds) {
			ds.setColor(Color.BLACK);
			ds.setUnderlineText(false); // 去掉下划线
		}

		@Override
		public void onClick(View widget) {
			// doNothing...
		}

	}

	public interface OnLinkClickListener {
		void onLinkClick();
	}

	/**
	 * 过滤掉一些不正常的链接
	 * 
	 * @param url
	 * @return
	 */
	public boolean isNormalUrl(URLSpan url) {
		String urlStr = url.getURL();
		if (urlStr.endsWith(".sh")) {
			return false;
		}
		return true;
	}
}
parseLinkText这个方法就是找到Html中的URl样式并设置自定义的ClickableSpan,这个主要调用了showLinkRedirect,我们上一篇文章已经说过了 ;setLinkText就是设置超链接的方法,首先会使用fromHtml拿出对应的Span然后设置Text然后解析这个Text。自定义TextView说完了,接下来就看看怎么使用它。

                listItemView.content.setLinkText(tweet.getBody());
		listItemView.content.setTag(tweet);// 设置隐藏参数(实体类)
		listItemView.content.setOnClickListener(linkViewClickListener);
		listItemView.content.setLinkClickListener(linkClickListener);
我们发现,这里设置了两个监听器setOnClickListener和setLinkClickListener,这是因为我们点击了超链接后其实是有两个操作的,一个是点击超链接的处理,一个是点击超链接之外的处理。如果不这样处理的话,那么就会出现上面说的不能响应其他事件。接下来我们再看看这两个监听器

      private View.OnClickListener linkViewClickListener = new View.OnClickListener() {
		public void onClick(View v) {
			if (!isLinkViewClick()) {
				UIHelper.showTweetDetail(v.getContext(),
						((Tweet) v.getTag()).getId());
			}
			setLinkViewClick(false);
		}
	};

	private OnLinkClickListener linkClickListener = new OnLinkClickListener() {
		public void onLinkClick() {
			setLinkViewClick(true);
		}
	};
这里只是设置了一个标志位

public abstract class MyBaseAdapter extends BaseAdapter {
	//标识LinkView上的链接
	private boolean isLinkViewClick = false;

	public boolean isLinkViewClick() {
		return isLinkViewClick;
	}

	public void setLinkViewClick(boolean isLinkViewClick) {
		this.isLinkViewClick = isLinkViewClick;
	}

}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值