Как использовать AsYouTypeFormatter TextWatcher в приложении для Android?

Я пытаюсь использовать AsYouTypeFormatter из libphonenumber Google с TextWatcher и не уверен, что это возможно. Мне удалось отформатировать текст, введенный из поля EditText, и вывести его в другом EditText, но я не смог напрямую изменить исходное поле EditText (это то, что я хочу). Я знаю о phoneNumberFormattingTextWatcher, но мы хотим, чтобы пользователь мог в конечном итоге выбрать, в какой локали он находится, и иметь больше контроля, чем это позволяет (из того, что я собрал).

Лучшие в классе:

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

Сначала я инициализирую AsYouTypeFormatter вверху своего класса:

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

После того, как мои вкладки и тому подобное созданы, я создаю поле EditText, форматирую внутри него существующий номер телефона (который работает) и присоединяю прослушиватель (который является текущим классом):

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);

Тогда это то, что у меня есть на данный момент в моих функциях TextWatcher, но я не уверен, в какой из этих функций должен быть мой код:

@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) {
}

Вот пример зарегистрированного вывода, поэтому я знаю, что форматирование работает:

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

И вот изображение вывода (верхний EditText — это phoneNumberText, а нижний — testPhoneNumberText): https://imgur.com/GXwRu.png

Что я хочу знать, так это то, как мне вернуть отформатированный вывод в исходный EditText по мере его ввода? Когда я пытаюсь это сделать, происходят странные вещи, такие как дублирование или просто показывается неформатированный. Я пробовал использовать s.replace(), но не уверен, что правильно его использую. Это возможно? Спасибо?


person sugarwaffle    schedule 03.01.2013    source источник
comment
Почему бы просто не использовать PhoneNumberFormattingTextWatcher(String countryCode)??? stackoverflow.com/a/29109236/1103584   -  person DiscDev    schedule 17.03.2015
comment
Для этого требуется minSdkVersion 21   -  person Lou Morda    schedule 04.08.2015
comment
@sugarwaffle У меня та же проблема, что и у вас. Как сделать так, чтобы текст форматировался по мере того, как пользователь печатает? Похоже, что AsYouTypeFormatter ничего не делает. Я не хочу форматировать потом, я хочу форматировать по мере ввода номера телефона. Любые решения?   -  person portfoliobuilder    schedule 12.04.2018


Ответы (2)


Для других, которые просто хотят отформатировать введенный пользователем номер телефона в EditText по мере того, как пользователь вводит, гораздо проще использовать PhoneNumberFormattingTextWatcher (встроенный в Android), чем пытаться любой из этих подробных ответов - и это ОДНА СТРОКА ИЗ КОД!

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

Вы также можете передать регион, выбранный пользователем, который, я думаю, фактически ответит на вопрос OP, но он не был доступен до API 21:

//This version takes a country code!
this.editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher("US"));
person DiscDev    schedule 17.03.2015
comment
Это требует, чтобы вы объявили minSdkVersion 21, что, вероятно, не подходит для большинства проектов прямо сейчас. - person Lou Morda; 04.08.2015
comment
@LouisMorda передает только регион, требующий minSdkVersion из 21 - вы можете отслеживать регион другими способами (как я делаю в своем проекте), чтобы поддерживать более низкий minSdkVersion, я просто указал, что он доступен. - person DiscDev; 05.08.2015
comment
Согласно нескольким другим сообщениям SOF и моему личному опыту, это работает только на ограниченном количестве устройств. Почему, я не знаю. - person Nick; 19.10.2015
comment
PhoneNumberFormattingTextWatcher не позволяет изменить формат номера. В моем текущем проекте требуется номер телефона в формате: ###-###-####, что не позволяет использовать PhoneNumberFormattingTextWatcher. - person Mick; 19.02.2019

В итоге я объявил новую строку вверху:

private String unformattedPhoneNumber;

Затем изменив мой код на это:

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

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

           }
           Log.v("AsYouTypeFormatter - source after loop", s.toString());

           phoneNumberText.setText(formattedPhoneNumber);
           aytf.clear();
       }

       formattedPhoneNumber = null;
       isInAfterTextChanged = false;
   }
}

Кажется, что aytf не смог отформатировать уже частично отформатированные телефонные номера, поэтому мне пришлось удалить все нецифры перед повторной отправкой в ​​​​aytf? Единственная оставшаяся проблема заключается в том, что курсор в поле EditText теперь находится в начале, а не в конце, но это не должно быть проблемой для исправления. Ура.

ИЗМЕНЕННЫЙ КОД:

@Override
public void afterTextChanged(Editable s) {
    if (!isInAfterTextChanged) {
        isInAfterTextChanged = true;
        phoneNumberText.setText(pnu.updateNationalNumber(s.toString()));
        phoneNumberText.setSelection(this.phoneNumberText.getText().length());
        isInAfterTextChanged = false;
    }
}

 /**
 * Updates the national number based on the param s
 * Takes all formatting out of param s and then reformats the number
 * using the AsYouTypeFormatter for libphonenumber and based upon
 * the region code
 *  
 * @param s The formatted value to be used to update the national number
 * @return String The new formatted national number
 */
public String updateNationalNumber(String s){
    //Instantiate the as you type formatter with the current region (US or UK)
    aytf = phoneUtil.getAsYouTypeFormatter(this.currentRegionCode.getCountryCode());
    String fNationalNumber = null;

    //Format the string
    if(s.length() > 0){
        String digitString = null;
        //If it's in the US remove all leading 1s (international code)
        if(this.currentRegionCode == RegionCode.US){
            digitString = new String(s.replaceAll("(^[1?])|([^\\d.])", ""));
        }
        //If it's in the UK remove all leading 44s (international code)
        else if (this.currentRegionCode == RegionCode.GB){
            digitString = new String(s.replaceAll("(^[4?]{2})|([^\\d.])", ""));
        }
       if(digitString != null){
           //RE input all of the digits into the formatter
           for(int i = 0; i < digitString.length(); i++){
               fNationalNumber = aytf.inputDigit(digitString.charAt(i));
           }
       }

       //Clear the formatter for the next round of input
       aytf.clear();

       //Try to update the phone number with the formatted number
       try {
           phoneUtil.parse(fNationalNumber, this.currentRegionCode.getCountryCode(), this.uPhoneNumber);
       //Rejects if the number isn't in an acceptable format for the region code given etc.
       } catch (NumberParseException e) {
          System.err.println("NumberParseException was thrown: " + e.toString());
       }
    }
    //Return the formatted phone number
    return fNationalNumber;
}
person sugarwaffle    schedule 03.01.2013
comment
Я не могу добавить специальные символы, такие как +, (,) и т. д., что делать? - person Sreekanth Karumanaghat; 01.02.2013
comment
Вы не должны добавлять +, (,) с помощью этого средства форматирования, оно должно добавлять его за вас. Не могли бы вы уточнить, что вы пытаетесь сделать? - person sugarwaffle; 04.02.2013
comment
Предположим, пользователь пытается ввести числа с предполагаемыми символами, я думаю, он должен это принять :) - person Sreekanth Karumanaghat; 05.02.2013
comment
На данный момент он должен разрешать пользователю вводить эти символы, но удалять их. Насколько я знаю, AYTF не будет принимать частично отформатированные номера телефонов с этими символами, он возвращает недействительный номер телефона и не понимает, как их форматировать. - person sugarwaffle; 06.02.2013
comment
Этот код просто выглядит как злоупотребление AsYouTypeFormatter. Вы просматривали его исходный код или связывались с кем-либо из сопровождающих, чтобы узнать, как его использовать? На сайте проекта видно, что код был включен в Android начиная с Ice Cream Sandwich, который используется фреймворком Android начиная с 4.0 (Ice Cream Sandwich). – code.google.com/p/libphonenumber - person Norman H; 19.12.2013
comment
Ниже приведена библиотека, используемая внутри платформы Android для реализации класса PhoneNumberTextChangedListener. android.googlesource.com/ платформа/фреймворки/база/+/cd92588/ - person Norman H; 19.12.2013
comment
@NormanH Да, мы сверились с исходным кодом AsYouTypeFormatter. По общему признанию, прошло некоторое время с тех пор, как мы работали над этим кодом, поэтому я не могу вспомнить многих деталей нашей реализации, однако, если у вас есть другое предложение, пожалуйста, опубликуйте его. Кроме того, нам нужно было, чтобы он был совместим и с Gingerbread, а не только с Ice Cream. - person sugarwaffle; 22.01.2014