How to use the TextWatcher class in Android?

AndroidAndroid EdittextTextwatcher

Android Problem Overview


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.

Android Solutions


Solution 1 - 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
	}
});

Solution 2 - Android

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.
    The s parameter is the text before any change is applied.
    The start parameter is the position of the beginning of the changed part in the text.
    The count parameter is the length of the changed part in the s sequence since the start position.
    And the after parameter is the length of the new sequence which will replace the part of the s sequence from start to start+count.
    You must not change the text in the TextView from this method (by using myTextView.setText(String newText)).
onTextChanged(CharSequence s, int start, int before, int count)`
  • Similar to the beforeTextChanged method but called after the text changes.
    The s parameter is the text after changes have been applied.
    The start parameter is the same as in the beforeTextChanged method.
    The count parameter is the after parameter in the beforeTextChanged method.
    And the before parameter is the count parameter in the beforeTextChanged method.
    You must not change the text in the TextView from this method (by using myTextView.setText(String newText)).
afterTextChanged(Editable s)
  • You can change the text in the TextView from this method.
    /!\ Warning: When you change the text in the TextView, the TextWatcher will be triggered again, starting an infinite loop. You should then add like a boolean _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:

enter image description here


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();
        }
}

Solution 3 - Android

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)

enter image description here

Solution 4 - Android

For Kotlin use KTX extension function: (It uses TextWatcher as previous answers)

yourEditText.doOnTextChanged { text, start, count, after -> 
        // action which will be invoked when the text is changing
    }


import core-KTX:

implementation "androidx.core:core-ktx:1.2.0"

Solution 5 - Android

A little bigger perspective of the solution:

@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.yourlayout, container, false);
        View tv = v.findViewById(R.id.et1);
        ((TextView) tv).addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                 SpannableString contentText = new SpannableString(((TextView) tv).getText());
                 String contents = Html.toHtml(contentText).toString();
            }

            @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
            }
        });
	    return v;
	}

This works for me, doing it my first time.

Solution 6 - Android

Using TextWatcher in Android

Here is a sample code. Try using addTextChangedListener method of TextView

addTextChangedListener(new TextWatcher() {

		BigDecimal previousValue;
		BigDecimal currentValue;

		@Override
		public void onTextChanged(CharSequence s, int start, int before, int
				count) {
			if (isFirstTimeChange) {
				return;
			}
			if (s.toString().length() > 0) {
				try {
					currentValue = new BigDecimal(s.toString().replace(".", "").replace(',', '.'));
				} catch (Exception e) {
					currentValue = new BigDecimal(0);
				}
			}
		}

		@Override
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
			if (isFirstTimeChange) {
				return;
			}
			if (s.toString().length() > 0) {
				try {
					previousValue = new BigDecimal(s.toString().replace(".", "").replace(',', '.'));
				} catch (Exception e) {
					previousValue = new BigDecimal(0);
				}
			}
		}

		@Override
		public void afterTextChanged(Editable editable) {
			if (isFirstTimeChange) {
				isFirstTimeChange = false;
				return;
			}
			if (currentValue != null && previousValue != null) {
				if ((currentValue.compareTo(previousValue) > 0)) {
					//setBackgroundResource(R.color.devises_overview_color_green);
                    setBackgroundColor(flashOnColor);
				} else if ((currentValue.compareTo(previousValue) < 0)) {
					//setBackgroundResource(R.color.devises_overview_color_red);

					setBackgroundColor(flashOffColor);
				} else {
                    //setBackgroundColor(textColor);
				}
				handler.removeCallbacks(runnable);
				handler.postDelayed(runnable, 1000);
			}
		}
	});

Solution 7 - Android

Create custom TextWatcher subclass:

public class CustomWatcher implements TextWatcher {

    private boolean mWasEdited = false;

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

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

    }

    @Override
    public void afterTextChanged(Editable s) {

        if (mWasEdited){

            mWasEdited = false;
            return;
        }

        // get entered value (if required)
        String enteredValue  = s.toString();

        String newValue = "new value";

        // don't get trap into infinite loop
        mWasEdited = true;
        // just replace entered value with whatever you want
        s.replace(0, s.length(), newValue);

    }
}

Set listener for your EditText:

mTargetEditText.addTextChangedListener(new CustomWatcher());

Solution 8 - Android

    public class Test extends AppCompatActivity {

    EditText firstEditText;
    EditText secondEditText;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        firstEditText = (EditText)findViewById(R.id.firstEditText);
        secondEditText = (EditText)findViewById(R.id.secondEditText);

        firstEditText.addTextChangedListener(new EditTextListener());

    }

    private class EditTextListener implements TextWatcher {

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            secondEditText.setText(firstEditText.getText());
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    }
}

Solution 9 - Android

if you implement with dialog edittext. use like this:. its same with use to other edittext.

dialog.getInputEditText().addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int start, int before, int count) {
    }

    @Override
    public void onTextChanged(CharSequence charSequence, int start, int before, int count) {
        if (start<2){
                dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
            }else{
                double size =  Double.parseDouble(charSequence.toString());
                if (size > 0.000001 && size < 0.999999){
                    dialog.getActionButton(DialogAction.POSITIVE).setEnabled(true);
                }else{
                    ToastHelper.show(HistoryActivity.this, "Size must between 0.1 - 0.9");
                    dialog.getActionButton(DialogAction.POSITIVE).setEnabled(false);
                }

            }
    }

    @Override
    public void afterTextChanged(Editable editable) {

    }
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndroid developerView Question on Stackoverflow
Solution 1 - AndroidDinesh PrajapatiView Answer on Stackoverflow
Solution 2 - AndroidYairoproView Answer on Stackoverflow
Solution 3 - AndroidSuragchView Answer on Stackoverflow
Solution 4 - AndroidFrancisView Answer on Stackoverflow
Solution 5 - AndroidBerit LarsenView Answer on Stackoverflow
Solution 6 - AndroidAnanduView Answer on Stackoverflow
Solution 7 - AndroidDenisView Answer on Stackoverflow
Solution 8 - AndroidAjay ShresthaView Answer on Stackoverflow
Solution 9 - AndroidIzzamedView Answer on Stackoverflow