【问题标题】:Control onclicklistener in autolink enabled textview在启用自动链接的文本视图中控制 onclicklistener
【发布时间】:2010-09-02 06:30:13
【问题描述】:

我正在使用我在 XML 文件中设置了 autolink="web" 属性的 TextView。我还为此 TextView 实现了onClickListener。问题是,当 TextView 中的文本包含超链接时,如果我触摸该链接,链接会在浏览器中打开,但同时onClickListener 也会触发。我不想那样。

我想要的是,如果我触摸超链接 clickListener 不应该触发。只有当我触摸未超链接的文本部分时,它才会触发。有什么建议吗?

【问题讨论】:

  • 赞成一个很好的问题。但在我看来这是不可能的
  • 你必须将文本分隔为不同的文本视图,并设置单独的侦听器,想不出任何其他可能性

标签: android


【解决方案1】:

您可以使用 Textview 类的 getSelectionStart() 和 getSelectionEnd() 函数来解决此问题,

tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ClassroomLog.log(TAG, "Textview Click listener ");
        if (tv.getSelectionStart() == -1 && tv.getSelectionEnd() == -1) {
            //This condition will satisfy only when it is not an autolinked text
            //Fired only when you touch the part of the text that is not hyperlinked 
        }
    }
});

这可能是一个迟到的回复,但可能对那些正在寻找解决方案的人有用。

【讨论】:

  • 如果我点击文本外部以及 textview 中的链接,它仍然会打开链接视图,我只想在点击链接时发生这种情况。
  • 老兄救活这个!谢谢我的相反,我需要在它进入超链接之前进行一些预处理,所以只需将 -1 更改为 > 0 和 viola 它就可以了
  • 看看这个如果它不起作用stackoverflow.com/a/41603171/5873832
【解决方案2】:

one of the @CommonsWare post 有助于拦截自动链接OnClick 事件。

private void fixTextView(TextView tv) {
    SpannableString current = (SpannableString) tv.getText();
    URLSpan[] spans =
            current.getSpans(0, current.length(), URLSpan.class);

    for (URLSpan span : spans) {
        int start = current.getSpanStart(span);
        int end = current.getSpanEnd(span);

        current.removeSpan(span);
        current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
                0);
    }
}

public static class DefensiveURLSpan extends URLSpan {
    private String mUrl;

    public DefensiveURLSpan(String url) {
        super(url);
        mUrl = url;
    }

    @Override
    public void onClick(View widget) {
        // openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
        // super.onClick(widget); // or it will do as it is.
    }
}

简单地应用上面的代码如下。它将遍历所有可链接的文本并将点击事件替换为上述事件处理程序。

fixTextView(textViewContent);

【讨论】:

  • 那篇文章改变了一切。最后非常重要的注释:“请注意,您不想在 TextView 上调用 setText(),认为您将用修改后的版本替换文本。您正在修改 TextView 的文本在此 fixTextView() 方法中,因此 setText() 不是必需的。更糟糕的是,如果您使用的是 android:autoLink,setText() 会导致 Android 返回并再次添加 URLSpans。"
  • 非常好,正是我需要的
【解决方案3】:

您可以在 TextView 中设置属性 android:linksClickable="false",与 android:autoLink="web";这使链接可见,但不可点击。

【讨论】:

  • 我认为这会导致与要求相反的行为。
  • 但这正是我需要的:)
【解决方案4】:

如果你愿意,你可以使用下面的代码来自定义字符串中的可点击链接(基于this post):

用法:

final TextView textView = (TextView) findViewById(R.id.textView);
final Spanned text = Html.fromHtml(getString(...));
textView.setText(text);
textView.setMovementMethod(new LinkMovementMethodExt());

LinkMovementMethodExt.java

public class LinkMovementMethodExt extends LinkMovementMethod {
    private static LinkMovementMethod sInstance;

    public static MovementMethod getInstance() {
        if (sInstance == null)
            sInstance = new LinkMovementMethodExt();
        return sInstance;
    }

    @Override
    public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) {
        final int action = event.getAction();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
            final int x = (int) event.getX() - widget.getTotalPaddingLeft() + widget.getScrollX();
            final int y = (int) event.getY() - widget.getTotalPaddingTop() + widget.getScrollY();
            final Layout layout = widget.getLayout();
            final int line = layout.getLineForVertical(y);
            final int off = layout.getOffsetForHorizontal(line, x);
            final ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
            if (link.length != 0) {
                //do something with the clicked item...
                return true;
            }
        }
        return super.onTouchEvent(widget, buffer, event);
    }

}

【讨论】:

    【解决方案5】:

    使用 textView.getSelectionStart() 和 textView.getSelectionEnd()。如果您单击链接 textView.getSelectionStart() 和 textView.getSelectionEnd() 以外的任何文本,则为 -1。因此,通过在 onClickListner 中使用 if 条件,您可以单击链接时阻止 onClick 操作。

    //inside onClickListner
    
    if(textView.getSelectionStart()==-1&&textView.getSlectionEnd==-1){
    
        //onClick action
    }
    

    【讨论】:

      【解决方案6】:
      private void fixTextView(TextView tv) {
          SpannableString current = (SpannableString) tv.getText();
          URLSpan[] spans =
                  current.getSpans(0, current.length(), URLSpan.class);
      
          for (URLSpan span : spans) {
              int start = current.getSpanStart(span);
              int end = current.getSpanEnd(span);
      
              current.removeSpan(span);
              current.setSpan(new DefensiveURLSpan(span.getURL()), start, end,
                      0);
          }
      }
      
      public static class DefensiveURLSpan extends URLSpan {
      
          public final static Parcelable.Creator<DefensiveURLSpan> CREATOR =
                  new Parcelable.Creator<DefensiveURLSpan>() {
      
              @Override
              public DefensiveURLSpan createFromParcel(Parcel source) {
                  return new DefensiveURLSpan(source.readString());
              }
      
              @Override
              public DefensiveURLSpan[] newArray(int size) {
                  return new DefensiveURLSpan[size];
              }
      
          };
      
      private String mUrl;
      
      public DefensiveURLSpan(String url) {
          super(url);
          mUrl = url;
      }
      
          @Override
          public void onClick(View widget) {
              // openInWebView(widget.getContext(), mUrl); // intercept click event and do something.
              // super.onClick(widget); // or it will do as it is.
          }
      }
      

      在视图被声明(通过通货膨胀或findViewById)或添加到窗口(通过addView)后,您将在视图上调用fixTextView(textViewContent);

      这包括在扩展 Parcelable 时设置 CREATOR 的缺失要求。

      它被提议作为编辑,但被拒绝。不幸的是,现在未来的用户将不得不首先找出原始的不完整。不错,审稿人!

      【讨论】:

      • 您认为为什么需要它?您所指的答案在没有CREATOR 字段的情况下有效
      • @wzieba 这取决于您的目标 API、IDE 和错误设置。如果您想使用截断版本并且您的特定配置允许它,那么请务必使用。请注意,它可能随时停止工作。
      • 我仍然不明白目标 API 尤其是 IDE 是如何导致此代码中的任何错误的。如果您将任何示例发布到CREATOR 字段有意义的答案中,这将非常有用。
      【解决方案7】:

      Kotlin 版本

      类似于 Java 中的旧答案。简单地说:

      1. 在布局编辑器/XML 中,通过 autoLink 属性添加您想要超链接的事物类型。

        <TextView
            ...
            android:autoLink="web|phone|email" />
        
      2. 在 Kotlin 代码中将 onClickListener 添加到您的 TextView 以处理对纯文本部分的点击。检查 selectionStart 和 selectionEnd 以确保此人没有点击链接。

        binding.messageText.setOnClickListener { view ->
            if (binding.messageText.selectionStart == -1 && binding.messageText.selectionEnd == -1) {
                // do whatever you want when they click on the plain text part
            }
        }
        

      【讨论】:

        【解决方案8】:

        您可以试试这个,而不是使用 onClickListener。

        private void addLink() {
                tvLink = (TextView) findViewById(R.id.tvInfo2);
        
                String strURL = UrlLoader.getCodeUrl();
        
                // Make the url string clicable and take action in its onclick
                SpannableString spanUrl = SpannableString.valueOf(strURL);
                spanUrl.setSpan(new InternalURLSpan(new OnClickListener() {
                    public void onClick(View v) {
        
                        //Do Some action
                    }
                }), 0, spanUrl.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                tvLink.setText(spanUrl);
        
                // We probably also want the user to jump to your link by moving the
                // focus (e.g. using the trackball), which we can do by setting the
                // proper movement method:
                MovementMethod m = tvLink.getMovementMethod();
                if ((m == null) || !(m instanceof LinkMovementMethod)) {
                    if (tvLink.getLinksClickable()) {
                        tvLink.setMovementMethod(LinkMovementMethod.getInstance());
                    }
                }
            }
        

        同样在布局 XML 文件中,别忘了添加

        <TextView android:layout_width="wrap_content" android:linksClickable="true"
        android:layout_height="wrap_content" android:id="@+id/tvInfo2" android:text="@string/url_link" />
        

        【讨论】:

          【解决方案9】:

          只是添加

          textView.setMovementMethod(CustomLinkMovementMethod.getInstance());

          @binary 对那些方法不适用于他们的人的回答

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-01-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多