我们在给TextView设置超链接的时候,可能最简单的,Android已经给出了一个非常的简单的做法就是:
在xml中设置:
android:autoLink="web"
或者
//sp为SpannableString
Linkify.addLinks(sp, Linkify.WEB_URLS);
上边如果设置,就可以完成基本功能,但是安装在不同的手机上,超链接的颜色都会不同,比如vivo的一个机子上是黑色的,显示的样式也不一样!
所以,这里只能使用URLSpan手动去匹配,并设置颜色:
//注意:不要在xml配置android:autoLink属性
SpannableString sp = new SpannableString(str);
//这句很重要,也可以添加自定义正则表达式
Linkify.addLinks(sp, Linkify.WEB_URLS);
//主要是获取span的位置
URLSpan[] spans = sp.getSpans(0, str.length(), URLSpan.class);
//这里可以用过循环处理就可以动态实现文本颜色的差别化了
//设置高亮样式一
for (URLSpan span : spans) {
sp.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.base_blue)), sp.getSpanStart(span), sp.getSpanEnd(span), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
//SpannableString对象设置给TextView
mTv.setText(sp);
//设置TextView可点击
mTv.setMovementMethod(LinkMovementMethod.getInstance());
为什么会出现这样的问题,是因为LinkMovementMethod中onTouchEvent(MotionEvent event)
,在ACTION_UP
事件中,返回了true,表示这里已经消费了up事件,那么自然不会再响应它的点击事件!
所以,这里的解决方案:
我在stackoverflow上找到一个回答:listview-textview-with-linkmovementmethod-makes-list-item-unclickable
public class LinkTextView extends android.support.v7.widget.AppCompatTextView {
boolean dontConsumeNonUrlClicks = true;
boolean linkHit;
public LinkTextView(Context context) {
super(context);
}
public LinkTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LinkTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
linkHit = false;
boolean res = super.onTouchEvent(event);
if (dontConsumeNonUrlClicks)
return linkHit;
return res;
}
public static class LocalLinkMovementMethod extends LinkMovementMethod {
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) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
if (widget instanceof LinkTextView) {
((LinkTextView) widget).linkHit = true;
}
return true;
} else {
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return false;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
}
}
然后在使用的时候:
//设置TextView可点击,并且调用自定义的LinkMovementMethod,不是url,返回false,否则会消费掉点击事件
mTv.setMovementMethod(LinkTextView.LocalLinkMovementMethod.getInstance());
首先我们自定义一个TextView,定义一个布尔值,是否点击了超链接,然后我们继承LinkMovementMethod
,在他的onTouchEvent
中,如果确实是点击的span,则将上边的属性置为true,然后在TextView的onTouchEvent中,返回这个属性即可!(如果点击的是超链接,return true,如果不是超链接,则return false,事件会继续往下分发,检查是否注册的有点击事件,而去响应点击事件!)