How do I use AsYouTypeFormatter TextWatcher in Android App?

sugarwaffle picture sugarwaffle · Jan 3, 2013 · Viewed 9.1k times · Source

I am trying to use the AsYouTypeFormatter from Google's libphonenumber with TextWatcher and am not sure if it's possible. I have been able to format the text as typed from an EditText field and output it in another EditText but not able to change the original EditText field directly (which is what I want). I know about the phoneNumberFormattingTextWatcher but we want the user to be able to eventually select which locale they're in and have more control than using that allows (from what I have gathered).

Top of class:

private View phoneNumberView;
private EditText phoneNumberText;
private String formattedPhoneNumber;
private boolean isInAfterTextChanged;
private AsYouTypeFormatter aytf;

First I initialize the AsYouTypeFormatter at the top of my class:

aytf = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(Locale.getDefault().getCountry());

After my tabs and such are created, I create an EditText box, format the existing phone number inside of it (which works), and attach the listener (which is the current class):

phoneNumberView = inflater.inflate(R.layout.phone_number_setting, null);
phoneNumberText = (EditText) phoneNumberView.findViewById(R.id.dirty_phone_number);
phoneNumberText.setText(dirtyPhoneNumber);
for (int i = 0; i < dirtyPhoneNumber.length(); i++){
    phoneNumberText.setText(aytf.inputDigit(dirtyPhoneNumber.charAt(i)));
}
aytf.clear();
phoneNumberText.setText(dirtyPhoneNumber);
phoneNumberText.addTextChangedListener(this);

Then this is what I have at the moment in my TextWatcher functions, I am not sure which one of these functions my code should be in though:

@Override
public void afterTextChanged(Editable s) {
    if (!isInAfterTextChanged) {
           isInAfterTextChanged = true;

           if(s.length() > 0){
               Log.v("AsYouTypeFormatter - source", s.toString());
               for(int i = 0; i < s.length(); i++){
                   formattedPhoneNumber = aytf.inputDigit(s.charAt(i));
                   Log.v("AsYouTypeFormatter - formatted", formattedPhoneNumber);

               }
               Log.v("AsYouTypeFormatter - source after loop", s.toString());
             //The formatted output shows properly in this EditText but not when I try to put it back into the original one (phoneNumberText) 
               EditText testPhoneNumberText = (EditText) phoneNumberView.findViewById(R.id.testPhoneNumberText);  
               testPhoneNumberText.setText(formattedPhoneNumber);
               aytf.clear();
           }

           formattedPhoneNumber = null;
           isInAfterTextChanged = false;
       }        

}

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

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

Here is a sample of the logged output, so I know the formatting is working:

01-03 10:55:02.838: V/AsYouTypeFormatter - source(27114): 15552451234
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 1
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 15
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 1 55
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 1 555
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 1 555-2
01-03 10:55:02.838: V/AsYouTypeFormatter - formatted(27114): 1 555-24
01-03 10:55:02.850: V/AsYouTypeFormatter - formatted(27114): 1 555-245
01-03 10:55:02.850: V/AsYouTypeFormatter - formatted(27114): 1 555-245-1
01-03 10:55:02.850: V/AsYouTypeFormatter - formatted(27114): 1 555-245-12
01-03 10:55:02.850: V/AsYouTypeFormatter - formatted(27114): 1 555-245-123
01-03 10:55:02.850: V/AsYouTypeFormatter - formatted(27114): 1 555-245-1234
01-03 10:55:02.850: V/AsYouTypeFormatter - source after loop(27114): 15552451234

And here is the image of the output (top EditText is phoneNumberText and bottom is testPhoneNumberText): http://imgur.com/GXwRu.png

What I want to know is how do I get the formatted output back into the original EditText as it's being typed? When I try to do it, weird things happen like duplication or it just shows it unformatted. I've tried using s.replace() but I am not sure that I am using it properly. Is this possible? Thanks?

Answer

DiscDev picture DiscDev · Mar 17, 2015

For others out there who just want to format a user-entered phone number in an EditText as the user types, it's much, much easier to use PhoneNumberFormattingTextWatcher (built in to Android) than attempt any of these verbose answers - and it's ONE LINE OF CODE!

//Add a special listener for this instance that will format phone numbers on the fly.
this.editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());

You can also pass the region the user has selected, which I think would actually answer the OP's question, but it wasn't available until API 21:

//This version takes a country code!
this.editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher("US"));