0

I want to tap on a word in edit text. When the word is clicked, it should show a set of custom suggested words in a Popup window by which the former word can be replaced with the suggested word. Please help me how to do this. The suggestions should not be shown while I type the word.

  • Doesn't the EditText already do this since maybe at least Android 4.0? – OneCricketeer Apr 19 '16 at 23:34
  • Can you please give an example for that? – Partho Mandal Apr 19 '16 at 23:39
  • There is an image of it in this question. http://stackoverflow.com/q/9011944/2308683 – OneCricketeer Apr 19 '16 at 23:40
  • But I want to replace it with a custom set of words for that particular word only, and I don't want to include in android dictionary. I want the same feature, but using my own dictionary structure which will suggest only particular suggestions for those words. – Partho Mandal Apr 19 '16 at 23:49
  • You need to be more specific about the desired behavior. What makes a word "wrong"? Do you want your list to open for every word? How should you distinguish between a tap to reposition the cursor, and a tap to open the list? – Mike M. Apr 20 '16 at 01:25
  • Don't worry about the wrong part. Yes, I want my list to be open for every word. The list will be different for every word. What I am thinking is implement clickableSpan for each word. In the onClick method for each word, I am trying to set arrayAdapter in ListView for each of these words to show the suggested words. But I am getting errors. Please help me in this. – Partho Mandal Apr 20 '16 at 02:40
  • That's not how I'd do it, but if you want help fixing your current code, you need to post it, along with the errors you're getting. – Mike M. Apr 20 '16 at 02:55
  • Looks like `tokenList` is `null` in the `editText.setText()` call. – Mike M. Apr 20 '16 at 03:18
  • @MikeM. After fixing that error, I am getting the following error: 04-20 21:14:18.796 25967-25967/com.datumdroid.android.ocr.simple E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference Please give me suggestions regarding how to fix that error – Partho Mandal Apr 21 '16 at 04:21
  • `listview` is `null`. The `ListView` with ID `list` is apparently not in your current layout. – Mike M. Apr 21 '16 at 04:27
  • @MikeM. Thanks a lot !!! It worked. Now I will work on improving this feature. Do you know any way to include listview inside editText ? Such as the one shown in this link : http://stackoverflow.com/q/9011944/2308683 – Partho Mandal Apr 21 '16 at 04:43
  • Looks like a `PopupWindow` with a `ListView`. Getting it to align with a word in an `EditText` will take some work, though. – Mike M. Apr 21 '16 at 04:48

1 Answers1

0

I have implemented the required feature. This is not a very elegant solution. So, if you can make this code more efficient, you are welcome.

    String meow = "I dont like ASU at all"; // String supposed be set in edit text
    final String[] tokens = meow.split("\\s+");
    tokenList = new ArrayList<String>(Arrays.asList(tokens));

    //Create a custom dictionary file which will be used in Suggested words

    dictionary = new HashMap<String, List<String>>();
    dictionary.put("I", Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
    dictionary.put("dont", Arrays.asList("Mumbai", "Delhi", "Gwalior"));
    dictionary.put("like", Arrays.asList("Phoenix", "Tucson", "Flagstaff"));
    dictionary.put("ASU", Arrays.asList("UoFA", "UCSB", "UCLA"));
    dictionary.put("at", Arrays.asList("Sameeran", "Nikhil", "Aniket"));
    dictionary.put("all", Arrays.asList("asas", "dfdf", "tytyty"));
    dictionary.put("Gwalior", Arrays.asList("hardwork", "maketh", "luck"));


    if (meow != null || meow.length() != 0  ) {

        _field.setMovementMethod(LinkMovementMethod.getInstance());

         //set the text for edittext using addClickablePart() function
        _field.setText(addClickablePart(meow, tokenList), EditText.BufferType.SPANNABLE);

    }

    // This function regenerates the clickable span after word replaced
    public void tokenGenerator(){
    String editText_sentence = _field.getText().toString();
    _field.setMovementMethod(LinkMovementMethod.getInstance());
    String[] intermediate_tokens  = editText_sentence.split("\\s+");
    ArrayList<String> intermediate_tokenList = new ArrayList<String>(Arrays.asList(intermediate_tokens));
    _field.setText(addClickablePart(editText_sentence, intermediate_tokenList), EditText.BufferType.SPANNABLE);


    //addClickable function defined here
    public SpannableStringBuilder addClickablePart(String str, ArrayList<String> clickableWords) {
    SpannableStringBuilder ssb = new SpannableStringBuilder(str);

    for (final String clickableWord : clickableWords) {
        int idx1 = str.indexOf(clickableWord);
        int idx2 = 0;
        while (idx1 != -1) {
            idx2 = idx1 + clickableWord.length();
            final String clickString = str.substring(idx1, idx2);
           // ssb.setSpan(new TouchableSpan(clickString), idx1, idx2, 0);
            ssb.setSpan(new TouchableSpan(clickString) {
                @Override
                public void onClick(View view) {
                final Spanned s = _field.getText();
                final int start = s.getSpanStart(this);
                final int end = s.getSpanEnd(this);
                word = s.subSequence(start, end).toString();

                final PopupWindow popupWindow = new PopupWindow(SimpleAndroidOCRActivity.this);

                final ArrayList<String> bua = new ArrayList<String>(dictionary.get(clickableWord));
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_dropdown_item_1line,
                            bua);

                final ListView listview = new ListView(SimpleAndroidOCRActivity.this);
                final EditText addWord = new EditText(SimpleAndroidOCRActivity.this);
                addWord.requestFocusFromTouch();
                addWord.setInputType(InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE);
                addWord.setImeOptions(EditorInfo.IME_ACTION_DONE);
                addWord.setOnEditorActionListener(new TextView.OnEditorActionListener() {

                    //Press Done button to replace typed word
                    @Override
                    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                        if (actionId == EditorInfo.IME_ACTION_DONE) {
                            StringBuffer sb = new StringBuffer(s.toString());
                            sb.replace(start, end, addWord.getText().toString());
                            _field.setText(sb.toString());
                            tokenGenerator();
                            if (popupWindow != null) {
                                popupWindow.dismiss();
                            }
                        }
                        return false;
                    }
                });
                addWord.setHint("Add word");
                listview.setAdapter(adapter);
                listview.addFooterView(addWord,null, true);
                listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
                        int itemPosition = position;

                            String itemValue = (String) listview.getItemAtPosition(position);
                            StringBuffer sb = new StringBuffer(s.toString());
                            sb.replace(start, end, itemValue);
                            _field.setText(sb.toString());
                            tokenGenerator();
                            InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
                            imm.hideSoftInputFromWindow(view.getWindowToken(), 0);

                        if (popupWindow != null) {
                            popupWindow.dismiss();
                        }
                    }
                });

                    // some other visual settings for popup window
                    popupWindow.setFocusable(true);
                    popupWindow.setOutsideTouchable(true);
                    popupWindow.setWidth(400);
                    popupWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
                    popupWindow.setContentView(listview);
                    popupWindow.setBackgroundDrawable(new ColorDrawable(Color.rgb(229,197,175)));
                    int pos = _field.getSelectionStart();
                    Layout layout = _field.getLayout();
                    int line = layout.getLineForOffset(pos);
                    int baseline = layout.getLineBaseline(line);
                    int ascent = layout.getLineAscent(line);
                    int x = (int)layout.getPrimaryHorizontal(pos);
                    int y = baseline + ascent;
                    popupWindow.showAtLocation(view, Gravity.LEFT,x,y + 30);
                    popupWindow.showAsDropDown(view, 0, 0); // show popup like dropdown list

                }
            }, idx1, idx2, 0);
            idx1 = str.indexOf(clickableWord, idx2);
        }

    }

    return ssb;
}

The following is the definition for TouchableSpan class which extends clickableSpan class

public abstract class TouchableSpan extends ClickableSpan {

String clicked;
String word;

public TouchableSpan(String string) {
    super();
    clicked = string;
}

abstract public void onClick(View view);


@Override
public void updateDrawState(TextPaint ds) {
    super.updateDrawState(ds);
    ds.setUnderlineText(false);
    }

}

It will look something like this:

enter image description here