开发者

Control onclicklistener in autolink enabled textview

I am using a TextView for which I have set autolink="web" property in XML file. I have also implemented the onClickListener for this TextView. The problem is, when t开发者_StackOverflowhe text in TextView contains a hyperlink, and if I touch that link, the link opens in browser but simultaneously the onClickListener triggers too. I don't want that.

What I want is, if I touch the hyperlink the clickListener should not fire. It should only fire if I touch the part of the text that is not hyperlinked. Any suggestion?


You can achieve this using a work around in getSelectionStart() and getSelectionEnd() functions of the Textview class,

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

It may be a late reply, but may be useful to those who are searching for a solution.


one of the @CommonsWare post helps to intercept autolink OnClick event.

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.
    }
}

Apply above code simply as below. It will go through all linkable texts and replace click events to above event handler.

fixTextView(textViewContent);


You can set the property android:linksClickable="false" in your TextView, in conjuction with android:autoLink="web"; this makes the links visible, but not clickable.


if you wish, you can use the next code which allows to customize the clickable links within the string ( based on this post ) :

usage:

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

}


Kotlin version:

Similar to older answers in Java. Simply:

  1. In Layout Editor/XML, add the types of things you'd like to hyperlink via the autoLink property.

    <TextView
        ...
        android:autoLink="web|phone|email" />
    
  2. Add an onClickListener to your TextView in Kotlin code to handle clicks on the plain text part. Check to make sure the person didn't click on a link by checking selectionStart and 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
        }
    }
    


Use textView.getSelectionStart() and textView.getSelectionEnd().If u click any text other than link textView.getSelectionStart() and textView.getSelectionEnd() will be -1 .So by using a if condition in onClickListner you can block the onClick action when link is clicked .

//inside onClickListner

if(textView.getSelectionStart()==-1&&textView.getSlectionEnd==-1){

    //onClick action
}


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.
    }
}

You would then call fixTextView(textViewContent); on the view after it is declared (via inflation or findViewById) or added to the window (via addView)

This includes the missing requirement to set a CREATOR when extending a Parcelable.

It was proposed as an edit, but rejected. Unfortunately, now future users will have to find out the original one is incomplete first. Nice one, reviewers!


Instead of using a onClickListener, you can try this.

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

Also in the layout XML file , dont forget to add

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


Just adding

textView.setMovementMethod(CustomLinkMovementMethod.getInstance());

to @binary's answer for those whose the method did not work with them

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜