How to click or tap on a TextView text on different words?

19,599

Solution 1

I finally figured it out how to have multiple clickable parts in a TextView. It is important that they all have their own ClickableSpan! That is where I went wrong the first time testing it. If they have the same ClickableSpan instance, only the last set span is remembered.

I created a String with the required clickable area's surrounded by "[" and "]".

String sentence = "this is [part 1] and [here another] and [another one]";

and here is the set TextView, the setMovementMehthod is also mandatory:

textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(addClickablePart(sentence), BufferType.SPANNABLE);

I have created this function, which will handle the creation of the clickable area's:

private SpannableStringBuilder addClickablePart(String str) {
    SpannableStringBuilder ssb = new SpannableStringBuilder(str);

    int idx1 = str.indexOf("[");
    int idx2 = 0;
    while (idx1 != -1) {
        idx2 = str.indexOf("]", idx1) + 1;

        final String clickString = str.substring(idx1, idx2);
        ssb.setSpan(new ClickableSpan() {

            @Override
            public void onClick(View widget) {
                Toast.makeText(getView().getContext(), clickString,
                        Toast.LENGTH_SHORT).show();
            }
        }, idx1, idx2, 0);
        idx1 = str.indexOf("[", idx2);
    }

    return ssb;
}

Solution 2

Based on Boy's response (and thank you for your response which helped me a lot), here is another way I implemented it without this '[' and ']' chars using an inner class to describe clickable words :

import java.util.List;

import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.widget.TextView;

/**
 * Defines a TextView widget where user can click on different words to see different actions
 *
 */
public class ClickableTextView extends TextView {

    public ClickableTextView(Context context) {
        super(context);
    }

    public ClickableTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ClickableTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setTextWithClickableWords(String text, List<ClickableWord> clickableWords) {
        setMovementMethod(LinkMovementMethod.getInstance());
        setText(addClickablePart(text, clickableWords), BufferType.SPANNABLE);
    }

    private SpannableStringBuilder addClickablePart(String str, List<ClickableWord> clickableWords) {
        SpannableStringBuilder ssb = new SpannableStringBuilder(str);

        for (ClickableWord clickableWord : clickableWords) {
            int idx1 = str.indexOf(clickableWord.getWord());
            int idx2 = 0;
            while (idx1 != -1) {
                idx2 = idx1 + clickableWord.getWord().length();
                ssb.setSpan(clickableWord.getClickableSpan(), idx1, idx2, 0);
                idx1 = str.indexOf(clickableWord.getWord(), idx2);
            }
        }

        return ssb;
    }

    public static class ClickableWord {
        private String word;
        private ClickableSpan clickableSpan;

        public ClickableWord(String word, ClickableSpan clickableSpan) {
            this.word = word;
            this.clickableSpan = clickableSpan;
        }

        /**
         * @return the word
         */
        public String getWord() {
            return word;
        }

        /**
         * @return the clickableSpan
         */
        public ClickableSpan getClickableSpan() {
            return clickableSpan;
        }
    }
}

Hope this may help someone

EDIT : how to change link color and remove underline:

Create and use your own implementation of ClickableSpan like this :

//a version of ClickableSpan without the underline
public static class NoUnderlineClickableSpan extends ClickableSpan {
    private int color = -1;

    public void setColor(int color) {
        this.color = color;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false);
        if (this.color != -1) {
            ds.setColor(this.color);
        }
    }
}

Solution 3

It's much simpler to use HTML with links in TextView than creating multiple TextViews, taking care about layout, listeners etc.

In your activity or fragment:

    TextView mText = (TextView) findViewById(R.id.text_linkified);
    mText.setText(Html.fromHtml("Open <a href='myapp://my-activity'>My Activity</a> or" +
            " <a href='myapp://other-activity'>Other Activity</a>"));
    mText.setMovementMethod(LinkMovementMethod.getInstance());

In manifest

    <activity android:name=".MyActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="myapp" android:host="my-activity"/>
        </intent-filter>
    </activity>
    <activity android:name=".MyOtherActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT"/>
            <data android:scheme="myapp" android:host="other-activity" />
        </intent-filter>
    </activity>

Solution 4

I recommend this library: https://github.com/klinker24/Android-TextView-LinkBuilder

it fits your requirement very well.

A quick overview:

enter image description here

copied form project's readme:

  • Specify long and short click actions of a specific word within your TextView
  • Provide user feedback by highlighting the text when the user touches it Match single strings or use a regular expression to set clickable links to any text conforming to that pattern
  • Change the color of the linked text
  • Modify the transparency of the text's highlighting when the user touches it
  • Set whether or not you want the text underlined

The main advantage to using this library over TextView's autolink functionality is that you can link anything, not just web address, emails, and phone numbers. It also provides color customization and touch feedback.

Share:
19,599
RajaReddy PolamReddy
Author by

RajaReddy PolamReddy

I love programming. I mostly code in "Android", "ActionScript", "Adobe Flash", Adobe AS3, iOS, Objective-C . My App.. Image Crop Current applications BingoBash and Slots Bash SOreadytohelp

Updated on June 13, 2022

Comments

  • RajaReddy PolamReddy
    RajaReddy PolamReddy almost 2 years

    How to move to another view by click on text view with two different words. this is the string i am using.

    By clicking Sign Up, you are indicating that you have read and agree to the 
    Term of Use and Privacy Policy.
    

    i want to make these two words (Term of Use, Privacy Policy) in different color and clickable..

    i know ho to make color for a particular word. i want to make it clickable .

  • RajaReddy PolamReddy
    RajaReddy PolamReddy about 12 years
    i am not using url here just text i want to open new activity by clicking on text.
  • pawelzieba
    pawelzieba about 12 years
    If the text is not changing, for example it's declared in strings.xml then this is the way to do it. Just declare "clickable" texts as a url with actions pointing to your activities. In result you'll get just text which is opening new activity on click, depends on what part of text you're clicking.
  • Compaq LE2202x
    Compaq LE2202x over 10 years
    This is great but the displayed sentence String has [ and ], should it not be included in the displayed string?
  • Boy
    Boy over 10 years
    You can determine yourself if you want that, just change the source to your likings...
  • pawelzieba
    pawelzieba over 10 years
    I have edited answer because a troll was down voting.
  • Boy
    Boy about 10 years
    Nice! Great I could help you out with this...I think I will be using your class then again for my project :)
  • Robin Royal
    Robin Royal over 9 years
    bro this answer is awesome.You rock :-)
  • Göksel Güren
    Göksel Güren over 9 years
    Thank you, and @Boy Working perfect. Words look underlined and blue. How can i style it?
  • phyzalis
    phyzalis over 9 years
    You must define a custom ClickableSpan to use in ClickableWord. I will edit my response and add it
  • phyzalis
    phyzalis over 9 years
    You can have a look at my answer which is looping on all the words
  • phyzalis
    phyzalis over 9 years
    And if you want to pass Parcelable object to your new Activity?
  • Boy
    Boy over 9 years
    I do not know. Probably now I would create my own custom view to handle this if I would want to style it differently. Not sure though. Been a few years when I wrote this :)
  • phyzalis
    phyzalis over 9 years
    Look at the NoUnderlineClickableSpan class I wrote in my edited response. I didn't find any other way for the underline.
  • Lorensius W. L. T
    Lorensius W. L. T about 9 years
    Thank you..it really helped me.
  • dev_mg99
    dev_mg99 almost 9 years
    i want to check two tags(@ and # ) like [ ] this . can u give me any solution for do this
  • Sakthivel Appavu
    Sakthivel Appavu almost 9 years
    ssb.setSpan(new ClickableSpan() { Hi, how to remove this "widget", and refresh edittext. @Override public void onClick(View widget) { // how to remove this "widget", and refresh edittext. } }, idx1, idx2, 0);
  • Rishabh Srivastava
    Rishabh Srivastava almost 9 years
    how to change the colour>
  • Narendra Singh
    Narendra Singh over 8 years
    it sometimes works wrong......as when clicking here another....it shows toast message for one another
  • Boy
    Boy over 8 years
    @DroidWormNarendra maybe ssb needs to be initialized each time in the while loop instead of once outside of it?
  • Narendra Singh
    Narendra Singh over 8 years
    okay @Boy I have a little different requirement.....lets say I have a dynamic list of words, I need to make only those words clickable in the whole text of the textview. How to do so?
  • Boy
    Boy over 8 years
    have a look at the answer below, I think that will do it for you