TextView设置SpanableString后,假如有ClickSpan的话,还需要设置Movemethod才能正确响应点击事件。
假如TextView有ClickSpan并且自身还有点击响应的话,那么只会响应ClickSpan,而自身的点击事件则不会响应。
方案1,给TextView设置TouchListener,模拟MoveMethod的方式:
public class LinkMovementMethodOverride implements View.OnTouchListener{
//回调 点击TextView非clickspan的地方的回调
private ForumItemLinkedMethod.IClickNoSpan mIClickNoSpan;
public LinkMovementMethodOverride(ForumItemLinkedMethod.IClickNoSpan IClickNoSpan) {
mIClickNoSpan = IClickNoSpan;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
TextView widget = (TextView) v;
CharSequence text = widget.getText();
try {
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);
float lineRight = layout.getLineRight(line);
int off = layout.getOffsetForHorizontal(line, x);
boolean moreThentextEnd = (x-lineRight)>20;//点击位置超过行末太远
ClickableSpan[] link = getSpans(text,off);
if (!moreThentextEnd&&link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
}
return true;
} else {
if (action == MotionEvent.ACTION_UP) {
if(mIClickNoSpan!=null){
try {
mIClickNoSpan.onClickNoSpan();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//根据SpannedString 或者SpannableString(注意这俩不一样), 获取指定位置的span
private ClickableSpan[] getSpans(CharSequence text,int off) throws Exception {
if(text instanceof SpannedString){
SpannedString buffer = (SpannedString) text;
return buffer.getSpans(off, off, ClickableSpan.class);
}else if(text instanceof SpannableString){
SpannableString buffer = (SpannableString) text;
return buffer.getSpans(off, off, ClickableSpan.class);
}else{
throw new RuntimeException("hans:not support text");
}
}
}
关键代码:
//1.修正坐标
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
then:
//获取xy坐标在文字里的offset
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
float lineRight = layout.getLineRight(line);
int off = layout.getOffsetForHorizontal(line, x);
then:
获取指定位置的span,判断是不是Clickspan。。。
方案2:自定义LinkMoveMethod,貌似有时候没用,参考吧
public class ForumItemLinkedMethod extends LinkMovementMethod {
public interface IClickNoSpan{
void onClickNoSpan();
}
private IClickNoSpan mIClickNoSpan;
public ForumItemLinkedMethod(IClickNoSpan IClickNoSpan) {
mIClickNoSpan = IClickNoSpan;
}
@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);
float lineRight = layout.getLineRight(line);
boolean moreThentextEnd = (x-lineRight)>20;
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (!moreThentextEnd&&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]));
}
return true;
} else {
Selection.removeSelection(buffer);
if (action == MotionEvent.ACTION_UP) {
if(mIClickNoSpan!=null){
try {
mIClickNoSpan.onClickNoSpan();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return true;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
}
使用:
textContent.setMovementMethod(new ForumItemLinkedMethod());