带有可点击链接的Android TextView:如何捕获点击?

我有一个TextView呈现基本的HTML,包含2+链接。 我需要捕获点击链接并打开链接 – 在我自己的内部WebView(不在默认浏览器中)。

处理链接呈现最常见的方法似乎是这样的:

String str_links = "<a href='http://google.com'>Google</a><br /><a href='http://facebook.com'>Facebook</a>"; text_view.setLinksClickable(true); text_view.setMovementMethod(LinkMovementMethod.getInstance()); text_view.setText( Html.fromHtml( str_links ) ); 

但是,这会导致链接在默认的内部Web浏览器中打开(显示“完成操作使用…”对话框)。

我试图实现一个onClickListener,正确地获得点击链接时触发,但我不知道如何确定哪个链接被点击…

 text_view.setOnClickListener(new OnClickListener(){ public void onClick(View v) { // what now...? } }); 

或者,我试着创build一个自定义的LinkMovementMethod类并实现onTouchEvent …

 public boolean onTouchEvent(TextView widget, Spannable text, MotionEvent event) { String url = text.toString(); // this doesn't work because the text is not necessarily a URL, or even a single link... // eg, I don't know how to extract the clicked link from the greater paragraph of text return false; } 

想法?


示例解决scheme

我想出了一个解决scheme ,它parsingHTMLstring中的链接并使它们可点击,然后让您响应URL。

根据另一个答案 ,下面是一个函数setTextViewHTML(),它parsingHTMLstring中的链接并使其可点击,然后让您响应URL。

 protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span) { int start = strBuilder.getSpanStart(span); int end = strBuilder.getSpanEnd(span); int flags = strBuilder.getSpanFlags(span); ClickableSpan clickable = new ClickableSpan() { public void onClick(View view) { // Do something with span.getURL() to handle the link click... } }; strBuilder.setSpan(clickable, start, end, flags); strBuilder.removeSpan(span); } protected void setTextViewHTML(TextView text, String html) { CharSequence sequence = Html.fromHtml(html); SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class); for(URLSpan span : urls) { makeLinkClickable(strBuilder, span); } text.setText(strBuilder); text.setMovementMethod(LinkMovementMethod.getInstance()); } 

这可以通过使用Spannable String来简单地解决。你真正想要做什么(业务需求)对我来说有点不清楚,所以下面的代码不会给你的情况给出确切的答案,但我很小心,它会给你一些想法和您将能够根据以下代码解决您的问题。

正如你所做的,我也通过HTTP响应得到一些数据,我已经添加了一些额外的下划线的文字在我的情况“更多”和这个下划线的文本将打开点击事件的web浏览器。希望这会帮助你。

 TextView decription = (TextView)convertView.findViewById(R.id.library_rss_expan_chaild_des_textView); String dec=d.get_description()+"<a href='"+d.get_link()+"'><u>more</u></a>"; CharSequence sequence = Html.fromHtml(dec); SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); UnderlineSpan[] underlines = strBuilder.getSpans(0, 10, UnderlineSpan.class); for(UnderlineSpan span : underlines) { int start = strBuilder.getSpanStart(span); int end = strBuilder.getSpanEnd(span); int flags = strBuilder.getSpanFlags(span); ClickableSpan myActivityLauncher = new ClickableSpan() { public void onClick(View view) { Log.e(TAG, "on click"); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(d.get_link())); mContext.startActivity(intent); } }; strBuilder.setSpan(myActivityLauncher, start, end, flags); } decription.setText(strBuilder); decription.setLinksClickable(true); decription.setMovementMethod(LinkMovementMethod.getInstance()); 

你做了如下:

 text_view.setMovementMethod(LinkMovementMethod.getInstance()); text_view.setText( Html.fromHtml( str_links ) ); 

你有没有按照下面的相反顺序尝试?

 text_view.setText( Html.fromHtml( str_links ) ); text_view.setMovementMethod(LinkMovementMethod.getInstance()); 

没有:

 text_view.setLinksClickable(true); 

我有同样的问题,但很多文字混合在一起的链接和电子邮件。 我认为使用“autoLink”是一个更简单,更干净的方式来做到这一点:

  text_view.setText( Html.fromHtml( str_links ) ); text_view.setLinksClickable(true); text_view.setAutoLinkMask(Linkify.ALL); //to open links 

您可以设置Linkify.EMAIL_ADDRESSES或Linkify.WEB_URLS,如果只有其中一个要使用或从XML布局设置

  android:linksClickable="true" android:autoLink="web|email" 

可用选项有:无,网页,电子邮件,电话,地图,全部

使用本地的Linkify库 ,这是一种更清洁,更好的解决scheme。

例:

 Linkify.addLinks(mTextView, Linkify.ALL); 

我已经实现了一个小的类的帮助下,你可以处理长时间的TextView本身点击和点击TextView中的链接。

布局

 TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autoLink="all"/> 

TextViewClickMovement.java

 import android.content.Context; import android.text.Layout; import android.text.Spannable; import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.util.Patterns; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.TextView; public class TextViewClickMovement extends LinkMovementMethod { private final String TAG = TextViewClickMovement.class.getSimpleName(); private final OnTextViewClickMovementListener mListener; private final GestureDetector mGestureDetector; private TextView mWidget; private Spannable mBuffer; public enum LinkType { /** Indicates that phone link was clicked */ PHONE, /** Identifies that URL was clicked */ WEB_URL, /** Identifies that Email Address was clicked */ EMAIL_ADDRESS, /** Indicates that none of above mentioned were clicked */ NONE } /** * Interface used to handle Long clicks on the {@link TextView} and taps * on the phone, web, mail links inside of {@link TextView}. */ public interface OnTextViewClickMovementListener { /** * This method will be invoked when user press and hold * finger on the {@link TextView} * * @param linkText Text which contains link on which user presses. * @param linkType Type of the link can be one of {@link LinkType} enumeration */ void onLinkClicked(final String linkText, final LinkType linkType); /** * * @param text Whole text of {@link TextView} */ void onLongClick(final String text); } public TextViewClickMovement(final OnTextViewClickMovementListener listener, final Context context) { mListener = listener; mGestureDetector = new GestureDetector(context, new SimpleOnGestureListener()); } @Override public boolean onTouchEvent(final TextView widget, final Spannable buffer, final MotionEvent event) { mWidget = widget; mBuffer = buffer; mGestureDetector.onTouchEvent(event); return false; } /** * Detects various gestures and events. * Notify users when a particular motion event has occurred. */ class SimpleOnGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent event) { // Notified when a tap occurs. return true; } @Override public void onLongPress(MotionEvent e) { // Notified when a long press occurs. final String text = mBuffer.toString(); if (mListener != null) { Log.d(TAG, "----> Long Click Occurs on TextView with ID: " + mWidget.getId() + "\n" + "Text: " + text + "\n<----"); mListener.onLongClick(text); } } @Override public boolean onSingleTapConfirmed(MotionEvent event) { // Notified when tap occurs. final String linkText = getLinkText(mWidget, mBuffer, event); LinkType linkType = LinkType.NONE; if (Patterns.PHONE.matcher(linkText).matches()) { linkType = LinkType.PHONE; } else if (Patterns.WEB_URL.matcher(linkText).matches()) { linkType = LinkType.WEB_URL; } else if (Patterns.EMAIL_ADDRESS.matcher(linkText).matches()) { linkType = LinkType.EMAIL_ADDRESS; } if (mListener != null) { Log.d(TAG, "----> Tap Occurs on TextView with ID: " + mWidget.getId() + "\n" + "Link Text: " + linkText + "\n" + "Link Type: " + linkType + "\n<----"); mListener.onLinkClicked(linkText, linkType); } return false; } private String getLinkText(final TextView widget, final Spannable buffer, final MotionEvent event) { 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) { return buffer.subSequence(buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])).toString(); } return ""; } } } 

用法

 String str_links = "<a href='http://google.com'>Google</a><br /><a href='http://facebook.com'>Facebook</a>"; text_view.setText( Html.fromHtml( str_links ) ); text_view.setMovementMethod(new TextViewClickMovement(this, context)); 

链接

希望这个帮助! 你可以在这里find代码。

我只使用textView,并设置跨度的url和处理点击。

我发现这里非常优雅的解决scheme,而不是链接 – 据我所知,我想链接的string的哪一部分

处理textview链接点击我的android应用程序

在kotlin:

 fun linkify(view: TextView, url: String, context: Context) { val text = view.text val string = text.toString() val span = ClickSpan(object : ClickSpan.OnClickListener { override fun onClick() { // handle your click } }) val start = string.indexOf(url) val end = start + url.length if (start == -1) return if (text is Spannable) { text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) text.setSpan(ForegroundColorSpan(ContextCompat.getColor(context, R.color.orange)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } else { val s = SpannableString.valueOf(text) s.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) s.setSpan(ForegroundColorSpan(ContextCompat.getColor(context, R.color.orange)), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) view.text = s } val m = view.movementMethod if (m == null || m !is LinkMovementMethod) { view.movementMethod = LinkMovementMethod.getInstance() } } class ClickSpan(private val mListener: OnClickListener) : ClickableSpan() { override fun onClick(widget: View) { mListener.onClick() } interface OnClickListener { fun onClick() } } 

和用法:linkify(yourTextView,urlString,上下文)