How to use the TextWatcher class in Android?
Can anyone tell me how to mask the substring in EditText
or how to change EditText
substring input to password type or replace by another character like this 123xxxxxxxxx3455
String contents = et1.getText().toString();
et1.setText(contents.replace.substring(0, contents.length()-2),"*");
Please, tell me how I can use the TextWatcher
method in Android.
For use of the TextWatcher
...
et1.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
The TextWatcher
interface has 3 callbacks methods which are all called in the following order when a change occurred to the text:
beforeTextChanged(CharSequence s, int start, int count, int after)
- Called before the changes have been applied to the text.
Thes
parameter is the text before any change is applied.
Thestart
parameter is the position of the beginning of the changed part in the text.
Thecount
parameter is the length of the changed part in thes
sequence since thestart
position.
And theafter
parameter is the length of the new sequence which will replace the part of thes
sequence fromstart
tostart+count
.
You must not change the text in theTextView
from this method (by usingmyTextView.setText(String newText)
).
onTextChanged(CharSequence s, int start, int before, int count)`
- Similar to the
beforeTextChanged
method but called after the text changes.
Thes
parameter is the text after changes have been applied.
Thestart
parameter is the same as in thebeforeTextChanged
method.
Thecount
parameter is theafter
parameter in the beforeTextChanged method.
And thebefore
parameter is thecount
parameter in the beforeTextChanged method.
You must not change the text in theTextView
from this method (by usingmyTextView.setText(String newText)
).
afterTextChanged(Editable s)
- You can change the text in the
TextView
from this method.
/!\ Warning: When you change the text in theTextView
, theTextWatcher
will be triggered again, starting an infinite loop. You should then add like aboolean _ignore
property which prevent the infinite loop.
Exemple:
new TextWatcher() {
boolean _ignore = false; // indicates if the change was made by the TextWatcher itself.
@Override
public void afterTextChanged(Editable s) {
if (_ignore)
return;
_ignore = true; // prevent infinite loop
// Change your text here.
// myTextView.setText(myNewText);
_ignore = false; // release, so the TextWatcher start to listen again.
}
// Other methods...
}
Summary:
A ready to use class: TextViewListener
Personally, I made my custom text listener, which gives me the 4 parts in separate strings, which is, for me, much more intuitive to use.
/**
* Text view listener which splits the update text event in four parts:
* <ul>
* <li>The text placed <b>before</b> the updated part.</li>
* <li>The <b>old</b> text in the updated part.</li>
* <li>The <b>new</b> text in the updated part.</li>
* <li>The text placed <b>after</b> the updated part.</li>
* </ul>
* Created by Jeremy B.
*/
public abstract class TextViewListener implements TextWatcher {
/**
* Unchanged sequence which is placed before the updated sequence.
*/
private String _before;
/**
* Updated sequence before the update.
*/
private String _old;
/**
* Updated sequence after the update.
*/
private String _new;
/**
* Unchanged sequence which is placed after the updated sequence.
*/
private String _after;
/**
* Indicates when changes are made from within the listener, should be omitted.
*/
private boolean _ignore = false;
@Override
public void beforeTextChanged(CharSequence sequence, int start, int count, int after) {
_before = sequence.subSequence(0,start).toString();
_old = sequence.subSequence(start, start+count).toString();
_after = sequence.subSequence(start+count, sequence.length()).toString();
}
@Override
public void onTextChanged(CharSequence sequence, int start, int before, int count) {
_new = sequence.subSequence(start, start+count).toString();
}
@Override
public void afterTextChanged(Editable sequence) {
if (_ignore)
return;
onTextChanged(_before, _old, _new, _after);
}
/**
* Triggered method when the text in the text view has changed.
* <br/>
* You can apply changes to the text view from this method
* with the condition to call {@link #startUpdates()} before any update,
* and to call {@link #endUpdates()} after them.
*
* @param before Unchanged part of the text placed before the updated part.
* @param old Old updated part of the text.
* @param aNew New updated part of the text?
* @param after Unchanged part of the text placed after the updated part.
*/
protected abstract void onTextChanged(String before, String old, String aNew, String after);
/**
* Call this method when you start to update the text view, so it stops listening to it and then prevent an infinite loop.
* @see #endUpdates()
*/
protected void startUpdates(){
_ignore = true;
}
/**
* Call this method when you finished to update the text view in order to restart to listen to it.
* @see #startUpdates()
*/
protected void endUpdates(){
_ignore = false;
}
}
Example:
myEditText.addTextChangedListener(new TextViewListener() {
@Override
protected void onTextChanged(String before, String old, String aNew, String after) {
// intuitive use of parameters
String completeOldText = before + old + after;
String completeNewText = before + aNew + after;
// update TextView
startUpdates(); // to prevent infinite loop.
myEditText.setText(myNewText);
endUpdates();
}
}
Supplemental answer
Here is a visual supplement to the other answers. My fuller answer with the code and explanations is here.
- Red: text about to be deleted (replaced)
- Green: text that was just added (replacing the old red text)