-1

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

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141

3 Answers3

1

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)
Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • This is probably the easiest approach - there are a lot of ways a user can sneakily try and get around these limitations, including pasting in invalid text, or entering something like `88788` and then deleting the `7`. Just running an overall validation check to approve or reject a change will save you a lot of headaches – cactustictacs May 19 '23 at 21:34
0

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) {
    }
});
Sandesh Khutal
  • 1,712
  • 1
  • 4
  • 17
  • I don't think this will handle the user pasting more than one character at a time correctly or typing when the cursor is in the middle of the text. – Tenfour04 May 19 '23 at 16:16
0

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
}
Masoud Karimi
  • 171
  • 1
  • 9