24

I want to get a number input from the user into an EditText. It needs to be separated by spaces - every 4 characters. Example: 123456781234 -> 1234 5678 1234.

This is only for visual purpose. However, I need the String without spaces for further usage.

What is the easiest way I can do this?

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
user510164
  • 626
  • 1
  • 8
  • 17

14 Answers14

16

is this editext for credit card?
first create count variable

int count = 0;

then put this in your oncreate(activity) / onviewcreated(fragment)

ccEditText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start,
                                  int count, int after) { /*Empty*/}

    @Override
    public void onTextChanged(CharSequence s, int start, int before,
                              int count) { /*Empty*/ }

    @Override
    public void afterTextChanged(Editable s) {

        int inputlength = ccEditText.getText().toString().length();

        if (count <= inputlength && inputlength == 4 ||
                inputlength == 9 || inputlength == 14)){

            ccEditText.setText(ccEditText.getText().toString() + " ");

            int pos = ccEditText.getText().length();
            ccEditText.setSelection(pos);

        } else if (count >= inputlength && (inputlength == 4 ||
                inputlength == 9 || inputlength == 14)) {
            ccEditText.setText(ccEditText.getText().toString()
                    .substring(0, ccEditText.getText()
                            .toString().length() - 1));

            int pos = ccEditText.getText().length();
            ccEditText.setSelection(pos);
        }
        count = ccEditText.getText().toString().length();
    }
});
Cerberus
  • 8,879
  • 1
  • 25
  • 40
15

There is an easier way to achieve this:

editText.doAfterTextChanged { text ->
    val formattedText = text.toString().replace(" ", "").chunked(4).joinToString(" ")

    if (formattedText != text.toString()) {
        editText.setText(formattedText)
        editText.setSelection(editText.length())
    }
}

When you want to get the text without space, just do:

editText.text.toString().replace(" ","")
Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Valentin
  • 5,379
  • 7
  • 36
  • 50
  • 1
    That's not work. When I input '123456789012', I get ```9012 5678 1234``` which should be like ```1234 5678 9012``` – Kelvin Herwanda Tandrio Dec 02 '21 at 04:58
  • Nice succinct answer I'd just change the `editText.setSelection` call slightly so that the cursor in the `EditText` doesn't jump to the end of the text when the user adds or removes a character somewhere in the middle of the text. To see a concrete example of this, see the `afterTextChanged(editable:)` method that I've put together [here](https://github.com/adil-hussain-84/android-edittext-experiments/blob/main/app1/src/main/java/com/masabi/app/CardNumberEditText.kt). – Adil Hussain May 16 '23 at 15:21
12

as @waqas pointed out, you'll need to use a TextWatcher if your aim is to make this happen as the user types the number. Here is one potential way you could achieve the spaces:

StringBuilder s;
s = new StringBuilder(yourTxtView.getText().toString());

for(int i = 4; i < s.length(); i += 5){
    s.insert(i, " ");
}
yourTxtView.setText(s.toString());

Whenever you need to get the String without spaces do this:

String str = yourTxtView.getText().toString().replace(" ", "");
FoamyGuy
  • 46,603
  • 18
  • 125
  • 156
5

You need to use TextWatcher to achieve visual purpose spaces.

And use any simply split string by space logic to join it back or loop through the entire string per character wise and eliminate (char) 32 from the string

waqaslam
  • 67,549
  • 16
  • 165
  • 178
4

I have created a class that encapsulates the given behavior.

/**
 * Custom [TextWatcher] class that appends a given [separator] for every [interval].
 */
abstract class SeparatorTextWatcher(
    private val separator: Char,
    private val interval: Int
) : TextWatcher {

    private var dirty = false
    private var isDelete = false

    override fun afterTextChanged(editable: Editable?) {
        if (dirty) return

        dirty = true
        val text = editable.toString().handleSeparator()
        onAfterTextChanged(text)
        dirty = false
    }

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        // Empty
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        isDelete = before != 0
    }

    private fun String.handleSeparator(): String {
        val stringBuilder = StringBuilder(this)

        if (length > 0 && length.rem(interval + 1) == 0) {
            if (isDelete) {
                stringBuilder.deleteCharAt(length - 1)
            } else {
                stringBuilder.insert(length - 1, separator)
            }
        }

        return stringBuilder.toString()
    }

    /**
     * Subclasses must implement this method to get the formatted text.
     */
    abstract fun onAfterTextChanged(text: String)
}

Here's a snippet on how to use it:

editText.addTextChangedListener(object : SeparatorTextWatcher(' ', 4) {
            override fun onAfterTextChanged(text: String) {
                editText.run {
                    setText(text)
                    setSelection(text.length)
                }
            }
        })
Miltos
  • 166
  • 3
2

I searched lot for this here are the complete code in kotlin for card

  yourEditText.addTextChangedListener(object : TextWatcher {
        private val TOTAL_SYMBOLS = 19 // size of pattern 0000-0000-0000-0000
        private val TOTAL_DIGITS = 16 // max numbers of digits in pattern: 0000 x 4
        private val DIVIDER_MODULO =
            5 // means divider position is every 5th symbol beginning with 1
        private val DIVIDER_POSITION =
            DIVIDER_MODULO - 1 // means divider position is every 4th symbol beginning with 0
        private val DIVIDER = ' '
        override fun beforeTextChanged(
            s: CharSequence,
            start: Int,
            count: Int,
            after: Int
        ) { // noop
        }

        override fun onTextChanged(
            s: CharSequence,
            start: Int,
            before: Int,
            count: Int
        ) { // noop
        }

        override fun afterTextChanged(s: Editable) {
            if (!isInputCorrect(s, TOTAL_SYMBOLS, DIVIDER_MODULO, DIVIDER)) {

                var repl = buildCorrectString(
                        getDigitArray(s, TOTAL_DIGITS),
                DIVIDER_POSITION,
                DIVIDER
                )

                yourEditText.clearFocus();
                yourEditText.setText(repl);
               yourEditText.requestFocus();
                yourEditText.setSelection(repl!!.length);

            }
        }

        private fun isInputCorrect(
            s: Editable,
            totalSymbols: Int,
            dividerModulo: Int,
            divider: Char
        ): Boolean {
            var isCorrect =
                s.length <= totalSymbols // check size of entered string
            for (i in 0 until s.length) { // check that every element is right
                isCorrect = if (i > 0 && (i + 1) % dividerModulo == 0) {
                    isCorrect and (divider == s[i])
                } else {
                    isCorrect and Character.isDigit(s[i])
                }
            }
            return isCorrect
        }

        private fun buildCorrectString(
            digits: CharArray,
            dividerPosition: Int,
            divider: Char
        ): String? {
            val formatted = StringBuilder()
            for (i in digits.indices) {
                if (digits[i] != '\u0000') {
                    formatted.append(digits[i])
                    if (i > 0 && i < digits.size - 1 && (i + 1) % dividerPosition == 0) {
                        formatted.append(divider)
                    }
                }
            }
            return formatted.toString()
        }

        private fun getDigitArray(s: Editable, size: Int): CharArray {
          val digits = CharArray(size)
            var index = 0
            var i = 0
            while (i < s.length && index < size) {
                val current = s[i]
                if (Character.isDigit(current)) {
                    digits[index] = current
                    index++
                }
                i++
            }
            return digits
        }
    })
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
Pratik Gondil
  • 689
  • 1
  • 6
  • 17
1

Format of text is 000 000 0000

android edittext textwatcher format phone number like xxx-xxx-xx-xx

public class PhoneNumberTextWatcher implements TextWatcher {

private static final String TAG = PhoneNumberTextWatcher.class
        .getSimpleName();
private EditText edTxt;
private boolean isDelete;

public PhoneNumberTextWatcher(EditText edTxtPhone) {
    this.edTxt = edTxtPhone;
    edTxt.setOnKeyListener(new View.OnKeyListener() {

        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_DEL) {
                isDelete = true;
            }
            return false;
        }
    });
}

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

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

public void afterTextChanged(Editable s) {

    if (isDelete) {
        isDelete = false;
        return;
    }
    String val = s.toString();
    String a = "";
    String b = "";
    String c = "";
    if (val != null && val.length() > 0) {
        val = val.replace(" ", "");
        if (val.length() >= 3) {
            a = val.substring(0, 3);
        } else if (val.length() < 3) {
            a = val.substring(0, val.length());
        }
        if (val.length() >= 6) {
            b = val.substring(3, 6);
            c = val.substring(6, val.length());
        } else if (val.length() > 3 && val.length() < 6) {
            b = val.substring(3, val.length());
        }
        StringBuffer stringBuffer = new StringBuffer();
        if (a != null && a.length() > 0) {
            stringBuffer.append(a);
            if (a.length() == 3) {
                stringBuffer.append(" ");
            }
        }
        if (b != null && b.length() > 0) {
            stringBuffer.append(b);
            if (b.length() == 3) {
                stringBuffer.append(" ");
            }
        }
        if (c != null && c.length() > 0) {
            stringBuffer.append(c);
        }
        edTxt.removeTextChangedListener(this);
        edTxt.setText(stringBuffer.toString());
        edTxt.setSelection(edTxt.getText().toString().length());
        edTxt.addTextChangedListener(this);
    } else {
        edTxt.removeTextChangedListener(this);
        edTxt.setText("");
        edTxt.addTextChangedListener(this);
    }

}
}
ashishdhiman2007
  • 807
  • 2
  • 13
  • 28
1

cleaner version of @Ario's answer which follows the DRY principle:

private int prevCount = 0;
private boolean isAtSpaceDelimiter(int currCount) {
    return currCount == 4 || currCount == 9 || currCount == 14;
}

private boolean shouldIncrementOrDecrement(int currCount, boolean shouldIncrement) {
    if (shouldIncrement) {
        return prevCount <= currCount && isAtSpaceDelimiter(currCount);
    } else {
        return prevCount > currCount && isAtSpaceDelimiter(currCount);
    }
}

private void appendOrStrip(String field, boolean shouldAppend) {
    StringBuilder sb = new StringBuilder(field);
    if (shouldAppend) {
        sb.append(" ");
    } else {
        sb.setLength(sb.length() - 1);
    }
    cardNumber.setText(sb.toString());
    cardNumber.setSelection(sb.length());
}

ccEditText.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) {

    } 

    @Override 
    public void afterTextChanged(Editable s) {
        String field = editable.toString();
        int currCount = field.length();

        if (shouldIncrementOrDecrement(currCount, true)){
            appendOrStrip(field, true);
        } else if (shouldIncrementOrDecrement(currCount, false)) {
            appendOrStrip(field, false);
        }
        prevCount = cardNumber.getText().toString().length(); 
    } 
}); 
Phileo99
  • 5,581
  • 2
  • 46
  • 54
0

Here is a little help function. For your example you would call it with

addPadding(" ", "123456781234", 4);

/**
 * @brief Insert arbitrary string at regular interval into another string 
 * 
 * @param t String to insert every 'num' characters
 * @param s String to format
 * @param num Group size
 * @return
 */
private String addPadding(String t, String s, int num) {
    StringBuilder retVal;

    if (null == s || 0 >= num) {
        throw new IllegalArgumentException("Don't be silly");
    }

    if (s.length() <= num) {
        //String to small, do nothing
        return s;
    }

    retVal = new StringBuilder(s);

    for(int i = retVal.length(); i > 0; i -= num){
        retVal.insert(i, t);
    }
    return retVal.toString();
}
mach
  • 8,315
  • 3
  • 33
  • 51
0

change the live text while typing is some what difficult. we should handle the following issues.

a. cursor position b. we should allow the user delete the entered text.

The following code handle both the issues.

  1. Add TextWatcher to EditText, and get the text from "afterTextchanged()" and write your logic

    String str=""; int strOldlen=0;

        @Override
                public void afterTextChanged(Editable s) {
    
       str = edtAadharNumber.getText().toString();
                    int strLen = str.length();
    
    
                    if(strOldlen<strLen) {
    
                        if (strLen > 0) {
                            if (strLen == 4 || strLen == 9) {
    
                                str=str+" ";
    
                                edtAadharNumber.setText(str);
                                edtAadharNumber.setSelection(edtAadharNumber.getText().length());
    
                            }else{
    
                                if(strLen==5){
                                    if(!str.contains(" ")){
                                     String tempStr=str.substring(0,strLen-1);
                                        tempStr +=" "+str.substring(strLen-1,strLen);
                                        edtAadharNumber.setText(tempStr);
                                        edtAadharNumber.setSelection(edtAadharNumber.getText().length());
                                    }
                                }
                                if(strLen==10){
                                    if(str.lastIndexOf(" ")!=9){
                                        String tempStr=str.substring(0,strLen-1);
                                        tempStr +=" "+str.substring(strLen-1,strLen);
                                        edtAadharNumber.setText(tempStr);
                                        edtAadharNumber.setSelection(edtAadharNumber.getText().length());
                                    }
                                }
                                strOldlen = strLen;
                            }
                        }else{
                            return;
                        }
    
                    }else{
                        strOldlen = strLen;
    
    
                        Log.i("MainActivity ","keyDel is Pressed ::: strLen : "+strLen+"\n old Str Len : "+strOldlen);
                    }
    
                }
    }
    
  2. Here I am trying to add space for every four characters. After adding first space, then the length of the text is 5. so next space is after 9 characters like that.

    if (strLen== 4||strLen==9)

    1. Here another problem is cursor position, once you modify the text of the edittext, the cursor move to first place. so we need to set the cursor manually.

    edtAadharNumber.setSelection(edtAadharNumber.getText().length());

    1. My text length is only 12 characters. So I am doing manual calculations, if your text is dynamic then you write dynamic logic.
Kona Suresh
  • 1,836
  • 1
  • 15
  • 25
0

Assuming that you know the final length of the String, you could implement a TextWatcher this way:

override fun setUp(view: View?) {

    editText.addTextChangedListener(object : TextWatcher{
        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        }

        override fun onTextChanged(p0: CharSequence, p1: Int, p2: Int, p3: Int) {
            if(p2 == 0 && (p0.length == 4 || p0.length == 9 || p0.length == 14))
                editText.append(" ")
        }

        override fun afterTextChanged(p0: Editable?) {
        }
    })

You just add a space each 4-digits block. p2 == 0 is to assure the user is not deleting, otherwise he/she would get stock.

The code is in Kotlin, You can do it exactly the same way in Java.

kike
  • 4,255
  • 5
  • 23
  • 41
0

If someone still looking for answer, check format-edit-text library

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final FormatEditText editText1 = findViewById(R.id.edit_text_1);
        editText1.setFormat("---- ---- ---- ----");
    }
}

Reference https://stackoverflow.com/a/59742478/1679946

0

If you are using data binding Add

android:afterTextChanged="@{handler::afterTextChanged}"    

in EditText and afterTextChanged function is as follows:

fun afterTextChanged(s: Editable) {
    if (s.length > 0 && s.length % 5 === 0) {
        val c: Char = s.get(s.length - 1)
        if (space === c) {
            s.delete(s.length - 1, s.length)
        }
    }
    // Insert char where needed.
    if (s.length > 0 && s.length % 5 === 0) {
        val c: Char = s.get(s.length - 1)
        // Only if its a digit where there should be a space we insert a space
        if (Character.isDigit(c) && TextUtils.split(
                s.toString(),
                space.toString()
            ).size <= 3
        ) {
            s.insert(s.length - 1, space.toString())
        }
    }
}

space add like this

 private val space: Char = ' '

If you are using inputType="numberDigit" this will disable the '-' and ' ' chars, so I recommend using, inputType="phone"

Arjun Othayoth
  • 351
  • 3
  • 5
  • does this logic work even when we try to add remove a char in middle and add some new char on behalf – ASN May 12 '21 at 02:53
-1

Simple Answer

    YourEditText.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) {

            int len=s.toString().length();

            if (before == 0 && (len == 4 || len == 9 || len == 14 ))
                YourEditText.append(" ");
        }

        @Override
        public void afterTextChanged(Editable s) {


        }
    });
Gundu Bandgar
  • 2,593
  • 1
  • 17
  • 21