Android TextView 自动链接监听

介绍

Android 的 TextView 组件提供了自动链接的功能,可以识别文本中的链接、电话号码、电子邮件地址等,并且可以点击跳转到相应的应用或网页。在某些情况下,我们可能需要在用户点击链接时进行特定的操作,比如打开自定义的网页或执行特定的逻辑。本文将介绍如何在 Android 中监听 TextView 的自动链接点击事件,并提供示例代码进行演示。

自动链接类型

Android 的 TextView 支持以下几种自动链接类型:

  • phone:电话号码
  • mailto:电子邮件地址
  • web:网址
  • map:地图地址
  • all:包含以上所有类型

监听自动链接点击事件

要监听 TextView 的自动链接点击事件,可以通过设置一个 LinkMovementMethod 对象来实现。LinkMovementMethodandroid.text.method.MovementMethod 的一个实现类,用于处理链接的点击事件。下面是一个示例代码:

TextView textView = findViewById(R.id.textView);
textView.setAutoLinkMask(Linkify.ALL);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setLinkTextColor(Color.BLUE);
textView.setHighlightColor(Color.TRANSPARENT);

textView.setOnTouchListener((v, event) -> {
    TextView widget = (TextView) v;
    Object text = widget.getText();
    if (text instanceof Spannable) {
        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;
            } else {
                Selection.removeSelection(buffer);
            }
        }
    }

    return false;
});

上面的代码中,首先我们使用 setAutoLinkMask() 方法设置自动链接的类型为 Linkify.ALL,这样 TextView 就会自动识别并添加相应的链接。然后使用 setMovementMethod() 方法将 LinkMovementMethod 设置为 TextView 的移动方法,这样就可以处理链接的点击事件。接下来,我们设置链接的文本颜色为蓝色,并将点击时的背景颜色设置为透明。最后,通过设置一个触摸监听器来处理链接的点击事件。

在触摸监听器中,我们首先获取点击的坐标,然后根据坐标获取点击位置的偏移量。接着,我们使用 getSpans() 方法获取该位置的 ClickableSpan 对象,如果存在,则调用 onClick() 方法处理链接的点击事件。如果不存在,则移除当前的文本选择。

示例

下面是一个示例,演示了如何在点击链接时弹出一个 Toast 消息:

TextView textView = findViewById(R.id.textView);
textView.setAutoLinkMask(Linkify.ALL);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setLinkTextColor(Color.BLUE);
textView.setHighlightColor(Color.TRANSPARENT);

textView.setOnTouchListener((v, event) -> {
    TextView widget = (TextView) v;
    Object text = widget.getText();
    if (text instanceof Spannable) {
        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);
                    Toast.makeText(MainActivity.this, "点击了链接:" + buffer.subSequence(buffer.getSpanStart(link[0]), buffer.getSpan