前言
ClickableSpan
可以让我们在点击TextView
相应文字时响应点击事件,比如常用的URLSpan
,会在点击时打开相应的链接。而为了让TextView
能够响应ClickableSpan
的点击,我们需要为它设置LinkMovementMethod
,但是这个LinkMovementMethod
又有着很大的坑,接下来就总结下这些坑和我的解决办法。
LinkMovementMethod
的坑
1、点不准
这里将每个字符都设置上ClickableSpan
,并在点击时Toast
当前被点的字符(文字颜色和背景色应该是ClickableSpan
和LinkMovementMethod
自动帮我们设置的)。设置完LinkMovementMethod
后,你会发现自己明明没有点到相应的ClickableSpan
,却还是响应了点击事件,或者明明点到了却不响应,还有的都点到文字外面了,还是会有响应,如下图。
2、ellipsize
不起作用且TextView
会滚
将maxLines
设置为2
,ellipsize
为end
,却发现不起作用,而且整个TextView
变成可以滚动的了。
简单分析下
我们大致看下LinkMovementMethod
的实现。LinkMovementMethod
继承自ScrollingMovementMethod
,从名字可以看出来它是可以滚动的。他有一个onTouchEvent
方法,看来是处理点击事件的,它会在action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN
的时候去处理事件,获得点击位置的ClickableSpan
,在ACTION_UP
的时候响应点击事件。而在action == MotionEvent.ACTION_MOVE
的时候交给父类ScrollingMovementMethod
处理,这也就使TextView
可以滚动,整个TextView
可以滚动显示所有的文本,也就不会有ellipsize
的省略号了。
Android 这样处理LinkMovementMethod
可能是为了在大量文字时更方便地阅读,可以上下滚动,点击的时候点击的位置可以不遮挡要点击文字。但是在有些情况下就不太适用了,比如只是想缩略的显示两行文本,而点击时要点那儿是那儿,这就需要我们来自己处理TextView
的点击事件。
解决LinkMovementMethod
滚动的问题
我当时在stackoverflow
找到了
解决方法,需要设置TextView
的OnTouchListener
,然后自己处理点击事件,大致贴一下源码。
public static class ClickableSpanTouchListener implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!(v instanceof TextView)) {
return false;
}
TextView widget = (TextView) v;
CharSequence text = widget.getText();
if (!(text instanceof Spanned)) {
return false;
}
Spanned buffer = (Spanned) text;
int action = event.getAction();
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
int x = (