How can I prevent an EditText from accepting a character 4 times consecutively in Kotlin for Android?

52 Views Asked by At

How to make edittext not to accept same character 4 times consuctivelty. For example it can accept "888" and not "8888". And if user writes a same character 4 times then the edittext should stop taking input

I am not sure how to implement this with textwatcher

3

There are 3 best solutions below

1
Sandesh Khutal On

Welcome to platform @Umar Afzal

Try this

EditText editText = findViewById(R.id.editText);

editText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(20)});

editText.addTextChangedListener(new 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) {
        String text = s.toString();
        if (text.length() >= 4 && text.charAt(text.length() - 1) == text.charAt(text.length() - 2)
                && text.charAt(text.length() - 2) == text.charAt(text.length() - 3)
                && text.charAt(text.length() - 3) == text.charAt(text.length() - 4)) {
            editText.setText(text.substring(0, text.length() - 1));
            editText.setSelection(editText.getText().length());
        }
    }

    @Override
    public void afterTextChanged(Editable s) {
    }
});
1
Tenfour04 On

I think this is most clearly implemented using an InputFilter instead of TextWatcher. Then you don’t have to worry about putting the cursor in the right spot if you reject the change.

Figure out what the text would look like after the change and whether it's acceptable. Reject it if it's not.

fun CharSequence.hasConsecutiveChars(count: Int) {
    var cur: Char? = null
    var curCount = 0
    for (c in this) {
        if (c != cur) {
            cur = c
            curCount = 0
        }
        if (++curCount >= count) return true
    }
    return false
}

val filter = InputFilter { source, start, end, dest, dstart, dend ->
    val afterChange = source.replaceRange(start..end, dest.subSequence(dstart..dend))
    if (afterChange.hasConsecutiveChars(4)) "" else null
}
editText.setInputFilters(filter)
0
Masoud Karimi On

Try this snippet to handle it while the user is typing and also when a text is pasted into the edittext:

val MAX_CONSEQUENT_CHARS = 4
var internalStopFlag = false
input.doAfterTextChanged { editable ->
        if (internalStopFlag) return@doAfterTextChanged
        editable ?: kotlin.run {
            internalStopFlag = false
            return@doAfterTextChanged
        }

        if (editable.length < MAX_CONSEQUENT_CHARS) kotlin.run {
            internalStopFlag = false
            return@doAfterTextChanged
        }

        internalStopFlag = true

        var consequences = 1
        for (i in 1 until editable.length) {
            if (editable[i] == editable[i - 1]) {
                consequences++
            } else {
                consequences = 1
            }

            if (consequences >= MAX_CONSEQUENT_CHARS) {
                // Before making any changes to Editable be sure to reset the flag. Because
                // tht doAfterTextChange callback will immediately call with the new value of
                // the Editable

                internalStopFlag = false

                editable.delete(i, i + 1)

                // Every time you change the editable you need to break the loop,
                // because the callback will call again immediately
                break
          }
      }

      internalStopFlag = false
}