The problem is that if i Linkify the textView the underliyng ScrollView don't listen the sweep Gestures I've setted.Is there a way to have Linkify without messing with the underliyng view's gestures? I tried to override ontouchEvent and return false to ACTION_MOVE but the scrollview's gesture needs the ACTION_DOWN and ACTION_UP event to function. Is there a way to achieve that?
3 Answers
Linkify
applies to a movementMethod to the textView LinkMovementMethod
. That movement method thought it implements a scrolling vertically method it overrides any other scrolling method the parent has. Although touchEvent
can be dispached to the parent, the specific parent ScrollView
needed the whole sequence ACTION_DOWN
, ACTION_MOVE
, ACTION_UP
to perform (sweep detection).
So the solution to my problem is after Linkify to remove the textView's scrolling method and handle the LinkMovementMethod
link detection action in onTouchEvent
of the textView.
@override
public boolean onTouchEvent(MotionEvent event) {
TextView widget = (TextView) this;
Object text = widget.getText();
if (text instanceof Spanned) {
Spannable buffer = (Spannable) text;
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]));
}
return true;
}
}
}
return false;
}
This way i have the Link_Click detection (performed only with the user touches the link and not the whole textview) and i don't have the whole LinkMovementMethod.
@weakwire and @Ridicully answers are correct. I just created a small gist that you can re-use in your project.
This is the link: https://gist.github.com/amilcar-andrade/e4b76840da1dc92febfc
There is a small bad thing that TextView::setText(...) method utilizing autoLink flag,
if (mAutoLinkMask != 0) {
Spannable s2;
if (type == BufferType.EDITABLE || text instanceof Spannable) {
s2 = (Spannable) text;
} else {
s2 = mSpannableFactory.newSpannable(text);
}
if (Linkify.addLinks(s2, mAutoLinkMask)) {
text = s2;
type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;
/*
* We must go ahead and set the text before changing the
* movement method, because setMovementMethod() may call
* setText() again to try to upgrade the buffer type.
*/
mText = text;
// Do not change the movement method for text that support text selection as it
// would prevent an arbitrary cursor displacement.
if (mLinksClickable && !textCanBeSelected()) {
setMovementMethod(LinkMovementMethod.getInstance());
}
}
}
So I spent a time to understand, why i'm disabling links in ListView item, but it obtains a link sometimes!
You need to set that flag in needed value and then call a setText(...)