Search code examples
androidkotlinandroid-edittextphone-numberandroid-textwatcher

Phone number auto formatting in android


I need to format a phone number in an edit text in android as per this format (222) 222-2222 ext222222 I have created a watcher that does the auto formatting for me. The watcher works fine and formats the phone number correctly. My only issue is when somebody manually goes to some other position within the entered phone and starts deleting or adding numbers then the auto formatting does not work. Any ideas how to go about with this issue. Here is how my current watcher looks like:

editText.addTextChangedListener(object : TextWatcher {
    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}

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

    override fun afterTextChanged(s: Editable) {
        val text = editText.text.toString()
        val textLength = editText.text.length
        if (text.endsWith("-") || text.endsWith(" ")) {
            return
        }
        if (textLength == 1) {
            if (!text.contains("(")) {
                editText.setText(StringBuilder(text).insert(text.length - 1, "(").toString())
                editText.setSelection(editText.text.length)
            }
        } else if (textLength == 5) {
            if (!text.contains(")")) {
                editText.setText(StringBuilder(text).insert(text.length - 1, ")").toString())
                editText.setSelection(editText.text.length)
            }
        } else if (textLength == 6) {
            editText.setText(StringBuilder(text).insert(text.length - 1, " ").toString())
            editText.setSelection(editText.text.length)
        } else if (textLength == 10) {
            if (!text.contains("-")) {
                editText.setText(StringBuilder(text).insert(text.length - 1, "-").toString())
                editText.setSelection(editText.text.length)
            }
        } else if (textLength == 15) {
            if (text.contains("-")) {
                editText.setText(StringBuilder(text).insert(text.length - 1, " ext").toString())
                editText.setSelection(editText.text.length)
            }
        }
    }
})

Solution

  • If all could depend upon me, this is how I could handle that(see comments between lines). This is only for the phone number formatting, assume it's a regional number with max 10 digits:

    phoneNumber.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) {
    
                    /* Let me prepare a StringBuilder to hold all digits of the edit text */
                        StringBuilder digits = new StringBuilder();
    
                     /* this is the phone StringBuilder that will hold the phone number */
    
                        StringBuilder phone = new StringBuilder();
    
                     /* let's take all characters from the edit text */
                        char[] chars = phoneNumber.getText().toString().toCharArray();
    
                       /* a loop to extract all digits */
                        for (int x = 0; x < chars.length; x++) {
                            if (Character.isDigit(chars[x])) {
                                /* if its a digit append to digits string builder */
                                digits.append(chars[x]);
                            }
                        }
    
    
                        if (digits.toString().length() >=3) {
                            /* our phone formatting starts at the third character  and starts with the country code*/
                            String countryCode = new String();
    
                            /* we build the country code */
                            countryCode += "(" + digits.toString().substring(0, 3) + ") ";
    
                            /** and we append it to phone string builder **/
                            phone.append(countryCode);
    
                            /** if digits are more than or just 6, that means we already have our state code/region code **/
                            if (digits.toString().length()>=6)
                            {
    
                                String regionCode=new String();
                                /** we build the state/region code **/
                                regionCode+=digits.toString().substring(3,6)+"-";
                                /** we append the region code to phone **/
                                phone.append(regionCode);
    
    
    
                                /** the phone number will not go over 12 digits  if ten, set the limit to ten digits**/
                                if (digits.toString().length()>=10)
                                {
                                    phone.append(digits.toString().substring(6,10));
                                }else
                                {
                                    phone.append(digits.toString().substring(6));
                                }
                            }else
                            {
                                phone.append(digits.toString().substring(3));
                            }
                            /** remove the watcher  so you can not capture the affectation you are going to make, to avoid infinite loop on text change **/
                            phoneNumber.removeTextChangedListener(this);
    
                            /** set the new text to the EditText **/
                            phoneNumber.setText(phone.toString());
                            /** bring the cursor to the end of input **/
                            phoneNumber.setSelection(phoneNumber.getText().toString().length());
                            /* bring back the watcher and go on listening to change events */
                            phoneNumber.addTextChangedListener(this);
    
                        } else {
                            return;
                        }
    
                }
            });
    

    This code will reformat the phone number every time the user changes the value of the EditText. I've tested it myself and it works and does not crash. You can test.

    EDIT: this is a java code but I think you can easily rewrite it into Kotlin.