PhoneNumberFormattingTextWatcher对特定美国手机号格式化失效问题
Problem Description
I'm using PhoneNumberFormattingTextWatcher to format US phone numbers as users type. However, when entering 1111111111, the formatting doesn't work at all. For other numbers like 2222222222, it correctly outputs the format (222)222-2222.
Here's my code snippet:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { edit_phone.addTextChangedListener(new PhoneNumberFormattingTextWatcher("US") { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Custom logic (if any) } // Other overridden methods (if any) }); }
Analysis & Solutions
1. Root Cause: libphonenumber's Validity Checks
The PhoneNumberFormattingTextWatcher relies on Google's libphonenumber library under the hood. The number 111-111-1111 is an invalid NANP (North American Numbering Plan) number—US area codes (the first 3 digits) can't be 111 (these are reserved/non-functional area codes). The library skips formatting for invalid numbers entirely, which is why numbers with valid area codes work as expected.
2. Fix Options
Option 1: Force Formatting (Ignore Validity)
If you just need consistent formatting regardless of whether the number is actually valid, implement a custom TextWatcher to handle the formatting manually:
edit_phone.addTextChangedListener(new TextWatcher() { private boolean isFormatting; @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) { if (isFormatting) return; isFormatting = true; // Strip all non-digit characters String digits = s.toString().replaceAll("\\D", ""); StringBuilder formatted = new StringBuilder(); if (!digits.isEmpty()) { formatted.append("(").append(digits.substring(0, Math.min(3, digits.length()))); if (digits.length() >= 3) { formatted.append(")"); formatted.append(digits.substring(3, Math.min(6, digits.length()))); if (digits.length() >= 6) { formatted.append("-").append(digits.substring(6, Math.min(10, digits.length()))); } } } s.replace(0, s.length(), formatted.toString()); isFormatting = false; } });
Option 2: Skip Validity Checks (Advanced)
If you want to stick with the official PhoneNumberFormattingTextWatcher, you could try bypassing the validity check via reflection or a custom PhoneNumberUtil instance. Note that this is risky—it relies on internal APIs that might break with system updates.
Option 3: Guide Users to Enter Valid Numbers
Add a real-time validity check and show a friendly prompt (e.g., "Please enter a valid US area code") when users input invalid prefixes, guiding them to use legitimate area codes.
3. Quick Validation Test
You can confirm the validity issue directly with libphonenumber's core methods:
PhoneNumberUtil util = PhoneNumberUtil.getInstance(); try { Phonenumber.PhoneNumber number = util.parse("1111111111", "US"); Log.d("PHONE", "Is valid: " + util.isValidNumber(number)); // Returns false Log.d("PHONE", "Formatted: " + util.format(number, PhoneNumberUtil.PhoneNumberFormat.NATIONAL)); } catch (NumberParseException e) { e.printStackTrace(); }
This will confirm that 1111111111 is marked as invalid, so the library won't format it.
内容的提问来源于stack exchange,提问作者Monica M

