select a word on a tap in TextView/EditText

12,206

UPDATE: Another better approach is to use BreakIterator:

private void init() {
    String definition = "Clickable words in text view ".trim();
    TextView definitionView = (TextView) findViewById(R.id.text);
    definitionView.setMovementMethod(LinkMovementMethod.getInstance());
    definitionView.setText(definition, BufferType.SPANNABLE);
    Spannable spans = (Spannable) definitionView.getText();
    BreakIterator iterator = BreakIterator.getWordInstance(Locale.US);
    iterator.setText(definition);
    int start = iterator.first();
    for (int end = iterator.next(); end != BreakIterator.DONE; start = end, end = iterator
            .next()) {
        String possibleWord = definition.substring(start, end);
        if (Character.isLetterOrDigit(possibleWord.charAt(0))) {
            ClickableSpan clickSpan = getClickableSpan(possibleWord);
            spans.setSpan(clickSpan, start, end,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
    }
}

private ClickableSpan getClickableSpan(final String word) {
    return new ClickableSpan() {
        final String mWord;
        {
            mWord = word;
        }

        @Override
        public void onClick(View widget) {
            Log.d("tapped on:", mWord);
            Toast.makeText(widget.getContext(), mWord, Toast.LENGTH_SHORT)
                    .show();
        }

        public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
        }
    };
}

OLD ANSWER

I wanted to handle click in my own Activity. I solved it by following code:

private void init(){
    String definition = "Clickable words in text view ".trim();
    TextView definitionView = (TextView) findViewById(R.id.definition);
    definitionView.setMovementMethod(LinkMovementMethod.getInstance());
    definitionView.setText(definition, BufferType.SPANNABLE);

    Spannable spans = (Spannable) definitionView.getText();
    Integer[] indices = getIndices(
            definitionView.getText().toString(), ' ');
    int start = 0;
    int end = 0;
      // to cater last/only word loop will run equal to the length of indices.length
    for (int i = 0; i <= indices.length; i++) {
        ClickableSpan clickSpan = getClickableSpan();
       // to cater last/only word
        end = (i < indices.length ? indices[i] : spans.length());
        spans.setSpan(clickSpan, start, end,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        start = end + 1;
    }
}
private ClickableSpan getClickableSpan(){
     return new ClickableSpan() {
            @Override
            public void onClick(View widget) {
                TextView tv = (TextView) widget;
                String s = tv
                        .getText()
                        .subSequence(tv.getSelectionStart(),
                                tv.getSelectionEnd()).toString();
                Log.d("tapped on:", s);
            }

            public void updateDrawState(TextPaint ds) {
                 super.updateDrawState(ds);
            }
        };
}
public static Integer[] getIndices(String s, char c) {
    int pos = s.indexOf(c, 0);
    List<Integer> indices = new ArrayList<Integer>();
    while (pos != -1) {
        indices.add(pos);
        pos = s.indexOf(c, pos + 1);
    }
    return (Integer[]) indices.toArray(new Integer[0]);
}
Share:
12,206
M-Wajeeh
Author by

M-Wajeeh

https://www.linkedin.com/in/muhammadwajeeh [email protected]

Updated on June 17, 2022

Comments

  • M-Wajeeh
    M-Wajeeh almost 2 years

    How to select a word on a tap in TextView/EditText in android. I have some text in a TextView/EditText and when user taps on a word, I want that word to be selected and after that when I call getSelectedText() like method, it should return me the selected word. Any Help would be appreciated.

    My goal is to perform some action when user taps on a particular word in TextView/EditText.

  • M-Wajeeh
    M-Wajeeh over 12 years
    Excellent. But I wanted to handle click event via listener, not via Intents :)
  • Deepak G M
    Deepak G M almost 12 years
    This is the best answer if you are looking at listeners solution and not intents. Not all problems are linked with a URL or a schema. In my case, I was looking at a simple solution to get to know which word was tapped in a textview. There was no good solution till I saw this. This solution just works perfectly. It does the same thing as to what textview clickable does but the best part is we are in control to take relevant action. I did one change though to the above code. With the above code, all words appear as links but I did not want that. So just commented the super.updateDrawState.
  • Hardik Joshi
    Hardik Joshi about 11 years
    Thank you so much i working on this from last 2 days and finally I solve it by using your code. Thank you again.
  • Manu
    Manu over 10 years
    Thank you M-WaJeEh. Worked like a charm. And also thanks Deepak for that added bit which I wanted.
  • KK_07k11A0585
    KK_07k11A0585 almost 9 years
    @M-WaJeEh I have integrated the code provided by you, but I do not want the underline on every word. How can I remove this ? Please let me know
  • KK_07k11A0585
    KK_07k11A0585 almost 9 years
    @M-WajeEh Also, I want to give click event on the lines and I am using BreakIterator.getLineInstance() but it is not working. Please suggest me an example
  • M-Wajeeh
    M-Wajeeh almost 9 years
    @KK_07k11A0585 don't call super.updateDrawState(ds); to avoid underline effect and BreakIterator.getLineInstance() will work if you put "\n" in your strings, I don't think it will detect visual line breaks by TextView.
  • KK_07k11A0585
    KK_07k11A0585 almost 9 years
    @M-WaJeEh Thanks for your answer, my requirement is I have a textview and when user tap on it, I need to change the background color of the line on which he has tapped. Can I achieve this using getLineInstance ?? Please let me know
  • M-Wajeeh
    M-Wajeeh almost 9 years
    @KK_07k11A0585 No you can't use getLineInstance(), combine stackoverflow.com/a/6726707/1112882 with stackoverflow.com/a/6273546/1112882 to achieve what you are looking for.
  • Carlos Botero
    Carlos Botero almost 6 years
    To: M-Waje. public void updateDrawState(TextPaint ds) { ds.setColor(Color.WHITE); // Choose color ds.setUnderlineText(false); } // Saludos