Breiby
Breiby

Reputation: 553

Replace the text in an EditText of maxLength 1 when new text is entered

I am creating a screen where the user can enter a 4 digit pin code, and to do this I am using several EditText widgets with a maxlength of 1. What I want to achieve is that when an EditText is already filled in with a digit, the user should be able to replace that digit with another by simply giving another input.

I am using a TextWatcher to perform actions when the text has been edited. One idea I had was to set the maxlength to 2 and clear the EditText in beforeTextChanged. However, this method results in the first input clearing the field, and then the user has to give an input again to fill the field.

    private final TextWatcher textWatcher = new TextWatcher() {
    boolean _ignore = false;

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

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        if (_ignore) { return; }

        _ignore = true;
        EditText current = (EditText) getActivity().getCurrentFocus();
        if (current != null && current.length() > 0) {
            current.setText("");
        }
        _ignore = false;
    }

    @Override
    public void afterTextChanged(Editable s) {
        if (_ignore) { return; }
    }
};

A similar question was asked here, but all the answers were either wrong or missing the point. This does not seem like such an obscure case to me, so it is weird that I have not been able to find anything online. Any input would be appreciated!

Upvotes: 1

Views: 893

Answers (2)

Boldijar Paul
Boldijar Paul

Reputation: 5495

The accepted response has an issue, what if the user clicks on the edittext behind the 1st character? Then it will set the text to the last character there, which is the one it was already there. You need to check the difference with the last value from the edit

 fun addWatcher(editText: EditText, editTextToFocus: EditText) {
        var beforeText: CharSequence = ""
        val textWatched = object : TextWatcher {
            override fun beforeTextChanged(
                s: CharSequence,
                start: Int,
                count: Int,
                after: Int
            ) {
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (s.length >= 2) {
                    val beforeChars = beforeText.toList()
                    val newChar = s.toList().firstOrNull {
                        !beforeChars.contains(it)
                    } ?: s.toString().substring(s.length - 1, s.length)
                    editText.setText(newChar.toString())
                }
            }

            override fun afterTextChanged(s: Editable) {
                beforeText = s.toString()
                editTextToFocus.requestFocus()
            }

        }
        editText.addTextChangedListener(textWatched)
    }

Upvotes: 0

DAA
DAA

Reputation: 1386

You were going well! Set maxLenght to 2, and on text changed, check the input size. If it is 2, clear the first digit. This way, you won't clear it the first time the user enters the digit.

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    if (s.length() >= 2) {
        editText.setText(s.toString().substring(s.length() - 1, s.length()));
    }
}

Upvotes: 4

Related Questions