需求背景:
内容通知来自服务端的推送,因为不一样的活动需要,推送不一样的内容,内容的组成部分为html,都是前端的标签,可能有多个不同网址。
而app内,要使用TextView来显示html的内容,因为内容的不一样,以及内置的链接要适用跳转到app内的各个模块;
内容分析:
从需求来看,主要有以下几点注意:
1、活动内容不一致,html包含各种不同的格式;
2、内容都是html标签;
3、通知类型多,内含的网址可以跳到各个模块,这里就要求在识别网址时,要做分流;
4、一个通知可能含有几个不一样的网址;
技术分析:
1、在Android中Html.fromHtml()方法可以把Html标签内容转化为TextView所要显示的内容;
2、如何实现点击不同的链接可以跳转呢?一个TextView要实现内容可以点击,我们可以想到SpannableStringBuilder,设置setMovementMethod和setspan可以实现跳转了;
3、现在还有个攻克的难点,我怎么知道里面有多少条网址链接,我怎么知道点击哪个textview的哪个地方可以触发对应的链接呢?
查资料发现,html内容设置进去后,会set对应的setspan,这时候,我们可以使用
“URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);”
来获取总共有多少个网址链接,在根据spanned匹配的开始和结束,我们能够知道怎么去响应对应的链接了;
具体代码如下:
**
* Created by azhansy 2017/2/13.
* 显示 HTML 的textView
*/
public class HtmlTextView extends TextView {
public HtmlTextView(Context context) {
this(context, null);
}
public HtmlTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HtmlTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setMovementMethod(LocalLinkMovementMethod.getInstance());
}
public HtmlSpannableStringBuilder setHtmlText(String htmlText) {
return new HtmlSpannableStringBuilder(htmlText);
}
public static class LocalLinkMovementMethod extends LinkMovementMethod {
private static final long CLICK_DELAY = 500L;
private long lastClickTime;
static LocalLinkMovementMethod sInstance;
public static LocalLinkMovementMethod getInstance() {
if (sInstance == null)
sInstance = new LocalLinkMovementMethod();
return sInstance;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
//长按 和 点击过快 不执行点击事件
if (System.currentTimeMillis() - lastClickTime < CLICK_DELAY &&
!Utils.isFastDoubleClick(1000L)) {
link[0].onClick(widget);
}
} else {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
lastClickTime = System.currentTimeMillis();
}
return true;
} else {
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return false;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
}
public class HtmlSpannableStringBuilder extends SpannableStringBuilder {
/**
* @param htmlLinkText
*/
public HtmlSpannableStringBuilder(String htmlLinkText) {
updateClickSpan(htmlLinkText);
}
/**
* 更新Span
*
* @param htmlLinkText
*/
private void updateClickSpan(String htmlLinkText) {
setText(Html.fromHtml(htmlLinkText));
CharSequence text = getText();
if (text instanceof Spannable) {
int end = text.length();
Spannable sp = (Spannable) getText();
URLSpan[] urls = sp.getSpans(0, end, URLSpan.class);
SpannableStringBuilder style = new SpannableStringBuilder(text);
style.clearSpans(); // should clear old spans
for (URLSpan url : urls) {
// 设置Span
int startSpan = sp.getSpanStart(url);
int endSpan = sp.getSpanEnd(url);
if (startSpan >= 0) {
style.setSpan(new Clickable(new URLClickListener(url.getURL())), startSpan, endSpan, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
Logger.d("azhansy: 链接", url.getURL());
}
setText(style);
}
}
//TextView中的Span区域点击事件
class Clickable extends ClickableSpan implements View.OnClickListener {
private final View.OnClickListener mListener;
public Clickable(View.OnClickListener l) {
mListener = l;
}
@Override
public void onClick(View widget) {
mListener.onClick(widget);
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
ds.setColor(Color.parseColor("#556B95"));
}
}
private class URLClickListener implements View.OnClickListener {
private String url;
URLClickListener(String url) {
this.url = url;
}
@Override
public void onClick(View arg0) {
Logger.d("azhansy: 点击后的链接 ", url);
//这里可以分流点击的链接
}
}
}
}
}
}