6

i use a TextWatcher to change pressed key value. my goal is that replace some characters while typing. for example when i type keys, if reached "S" character, replaces it with "a" character. my question is: should i do it in beforeTextChanged?? how? can anyone give me an example?

Fcoder
  • 9,066
  • 17
  • 63
  • 100

4 Answers4

14

I know that this post is a couple of years old, but both versions did not work for me and have build a hybrid between the two answers.

@Override
public void afterTextChanged(Editable editable) {    
    if (editable.toString().contains(",")) {
       Editable ab = new SpannableStringBuilder(editable.toString().replace(",", ""));
       editable.replace(0, editable.length(), ab);
    }
}
tynn
  • 38,113
  • 8
  • 108
  • 143
quantum apps
  • 938
  • 2
  • 13
  • 25
  • This is better than accepted answer since it doesn't move the cursor position to front. – 林果皞 Jan 11 '19 at 10:54
  • 1
    In my case (not checking `,`), I also need to do `editTextView.removeTextChangedListener(this);` in the first line of this method to prevent infinite call this method over and over again. – 林果皞 Jan 11 '19 at 11:06
  • 1
    It is recommended to create boolean inside custom TextWatcher to prevent infinite loop, example class from Android team: PhoneNumberFormattingTextWatcher – Darek Deoniziak Mar 20 '20 at 08:46
1

Using beforeTextChanged won't be useful because it won't interrupt the actual printing of the key to the EditText. I would use something similar to:

    public void afterTextChanged(Editable s) {
        if(s.length() > 0 && s.toString().charAt(s.length()-1) == 'S')
        {
            final String newText = s.toString().substring(0, s.length()-1) + "a"; 
            editText.setText(newText); 
        }
    }

I added some toString()'s, not 100% sure how Editable works but I think that should cover it.

0xPixelfrost
  • 10,244
  • 5
  • 39
  • 58
RyPope
  • 2,645
  • 27
  • 51
  • "quantum apps" answer below is superior. TextWatcher shouldn't need to hold reference to editText instance, calling editText.setText from TextWatcher creates cursor problems. – Darek Deoniziak Mar 20 '20 at 08:52
1

You have to do it in the afterTextChanged, but don't forget to detach and reattach the TextChangedListener to prevent an endless loop.
A simple example is shown below :

public void afterTextChanged(Editable s) {
        editText.removeTextChangedListener(this);
        //.. do changes here ..//
        editText.setText(newText);
        editText.addTextChangedListener(this);
}

But there is another problem when you call setText, it causes the cursor to move to the end of the text inside the textView. So you have to calculate the new position for the curser yourself, remember user may enter the multiple characters at once by pasting or delete a selected part of the text.
Here is a more complete example. This watcher class removes all nonnumeric characters of the text.

public class NumWatcher implements TextWatcher {
    private EditText editText;
    private int selPos;
    private String oldString, newString;
    public NumWatcher(EditText editText) {
        this.editText = editText;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        selPos = editText.getSelectionStart();
        oldString = myFilter(s.toString());
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }

    @Override
    public void afterTextChanged(Editable s) {
        editText.removeTextChangedListener(this);
        newString = myFilter(s.toString());
        editText.setText(newString);
        int newPos = selPos + (newString.length() - oldString.length());
        if (newPos < 0) newPos = 0;
        editText.setSelection(newPos);
        editText.addTextChangedListener(this);
    }

    public String myFilter(String s) {
        String digits;
        digits = s.replaceAll("[^0-9]", "");
        if (s.equals("")) return "";
        return digits;
    }
}
ucMedia
  • 4,105
  • 4
  • 38
  • 46
  • 1
    Instead of holding reference of EditText in TextWatcher it is recommended to create boolean to prevent infinite loop. Take a look at PhoneNumberFormattingTextWatcher from Android team – Darek Deoniziak Mar 20 '20 at 08:55
-3
@Override
public void afterTextChanged(Editable arg0) {
    Editable ab = new SpannableStringBuilder(arg0.toString().replace("S", "a"));
    arg0 = ab ;
}
bsiamionau
  • 8,099
  • 4
  • 46
  • 73
Mobeen Altaf
  • 138
  • 1
  • 9