Android TextView Linkify会与父View手势冲突

8
问题是,如果我对textView进行Linkify处理,则底层的ScrollView不会监听我设置的滑动手势。有没有一种方法可以使文本链接化而不会影响底层视图的手势? 我尝试重写ontouchEvent并返回false到ACTION_MOVE,但ScrollView的手势需要ACTION_DOWN和ACTION_UP事件才能正常工作。有没有实现这一点的方法?
3个回答

47

Linkify应用于textView的movementMethod LinkMovementMethod。虽然该movement方法实现了一种垂直滚动方法,但它会覆盖父级具有的任何其他滚动方法。虽然touchEvent可以分派到父级,但特定的父级ScrollView需要整个序列ACTION_DOWNACTION_MOVEACTION_UP来执行(扫描检测)。

因此,我问题的解决方案是在Linkify后删除textView的滚动方法,并在textView的onTouchEvent中处理链接检测操作。

@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;
    }
这样我就可以检测到 Link_Click(仅在用户触摸链接而不是整个 TextView 时执行),并且不需要整个 LinkMovementMethod。

我很高兴它终于帮助到了某个人 :D - weakwire
1
不错的解决方案,清晰而且不是 hacky(指使用奇怪或有问题的方法)。但我必须将 return true; 移到内部 if 的正向分支中,以便在触摸保持稳定时突出显示 span。 - A-Live
2
所提到的“删除textView的滚动方法”是通过textView.setMovementMethod(null);实现的,必须在设置了textView的文本之后调用。 - Ridcully
谢谢,这节省了我很多时间! - Ilja S.

3

我已经将这个类移植到Xamarin/C#:https://gist.github.com/pmachapman/a988348a93933ac359ebe0d6a5314467 - Peter

0

有一件小事情,就是TextView::setText(...)方法使用了autoLink标志,

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());
            }
        }
    }

所以我花了一些时间去理解, 为什么我在ListView项中禁用链接, 但有时它会获取一个链接!

您需要将该标志设置为所需的值, 然后调用setText(...)


1
这里有点不太清楚你的意思。这是对问题的回答还是你想要提出一个新问题? - SuperBiasedMan
这主要是一条笔记,因为我在搜索“ListView中的Linkify TextView”问题时找到了这个主题。 - Mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接