19

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
  • 17,204
  • 10
  • 66
  • 103

2 Answers2

35

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]);
}
M-Wajeeh
  • 17,204
  • 10
  • 66
  • 103
  • 4
    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. – Deepak G M Aug 10 '12 at 09:25
  • Thank you so much i working on this from last 2 days and finally I solve it by using your code. Thank you again. – Hardik Joshi Mar 20 '13 at 17:15
  • 1
    Thank you M-WaJeEh. Worked like a charm. And also thanks Deepak for that added bit which I wanted. – Manu Dec 16 '13 at 15:57
  • @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 Jul 09 '15 at 08:01
  • @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 – KK_07k11A0585 Jul 09 '15 at 08:16
  • 1
    @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`. – M-Wajeeh Jul 09 '15 at 08:37
  • @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 – KK_07k11A0585 Jul 09 '15 at 09:32
  • 2
    @KK_07k11A0585 No you can't use `getLineInstance()`, combine http://stackoverflow.com/a/6726707/1112882 with http://stackoverflow.com/a/6273546/1112882 to achieve what you are looking for. – M-Wajeeh Jul 09 '15 at 09:51
  • To: M-Waje. public void updateDrawState(TextPaint ds) { ds.setColor(Color.WHITE); // Choose color ds.setUnderlineText(false); } // Saludos – Carlos Botero Aug 03 '18 at 23:05
0

Use Linkify, Use your own Regular Expression to invoke your routine on the click of a word.

See here for the WikiWord Example and Relevant Blogpost

st0le
  • 33,375
  • 8
  • 89
  • 89