2011-04-13 3 views
13

Я работаю над Android-приложением, и у меня есть EditText, где пользователь может вводить числа. Я хочу отформатировать номер, используя разные форматы валют (например, ##, ##, ###), и я хочу сделать это «на лету», т.е. когда пользователь вводит каждую цифру (а не при нажатии на ввод). Я искал googled, и наткнулся на TextWatcher, который я впервые нашел многообещающим, но это оказалось абсолютной болью. Я отлаживаю свой код на телефоне HTC Desire, который имеет только мягкую клавиатуру.android EditText, клавиатура textWatcher проблема

Теперь я хочу получить обратный вызов, когда пользователь нажимает цифры (от 0 до 9), клавишу del (backspace) и вводит ключ. Из моего тестирования я нашел это (по крайней мере на моем телефоне)

1) EditText onKeyListener называется , когда пользователь нажимает дель или клавишу ввода. Когда пользователь нажимает enter, onKey функция вызывается дважды для одного введите (который, я считаю, предназначен для ACTION_UP и ACTION_DOWN). Когда пользователь нажимает del, onKey вызывается один раз (только для ACTION_DOWN), который я не знаю, почему. onKey никогда не вызывается, когда пользователь нажимает любые цифры (от 0 до 9), которые тоже я не могу понять.

2) TextWatchers 3 функции обратного вызова называются (beforeTextChanged, OnTextChanged, afterTextChanged) всякий раз, когда пользователь нажимает любую клавишу (число от 0 до 9). Поэтому я подумал, используя TextWatcher и onKeyListener вместе Я могу получить все обратные вызовы, в которых я нуждаюсь.

Теперь мои вопросы таковы ..

1) Во-первых, в моем HTC мягкой клавиатурой там является ключевым (символ клавиатуры с стрелкой вниз), и когда я нажимаю на него клавиатуры уходит в отставку без предоставления любого обратного вызова. Я все еще не могу поверить андроид позволяет пользователю редактировать поле и уйти в отставку без пропуска программы до процесс (сохранить) редактирования. Теперь мой EditText показывает одно значение, и мой объект имеет другое значение (я спасаю редактирует пользователей на въезд, и обращение назад нажмите на клавиатуре на переустановку значение EditText со значением в объекта, но у меня нет ответа к этому клавиатура вниз ключ).

2) Во-вторых, я хочу отформатировать номер после ввода пользователем новой цифры. Скажите У меня уже есть 123 на editText и пользователь вводил нажатый 4, мне нужен мой editText для отображения 1,234. Я получаю полный номер на onTextChanged() и afterTextChanged(), и я могу отформатировать номер и вернуть его обратно в editText в любом из этих обратных вызовов. Какой я должен использовать? Что является лучшей практикой ?

3) Третий - самая важная проблема . При запуске приложения я помещаю текущее значение объекта в editText. Скажем, я положил 123 на onResume(), и когда пользователь вводит цифру (скажем 4) Я хочу это быть 1234.Но на мой onTextChanged callback я получаю 4123. Когда нажимаю еще одну клавишу (скажем 5), я получаю 45123. Так что для пользовательских входов editText курсор указывает на конец текст. Но когда значение задано стороны, editText-курсор не кажется обновление. Я считаю, что мне нужно сделать что-то в текстовых обратных вызовах, но Я не знаю, что я должен делать.

Я отправляю свой код ниже.

public class AppHome extends AppBaseActivity { 
    private EditText ed = null; 
    private NumberFormat amountFormatter = null; 
    private boolean isUserInput = true; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.app_home_screen); 

     ed = (EditText)findViewById(R.id.main_amount_textfield); 
     amountFormatter = new DecimalFormat("##,##,###"); 


     ed.setOnKeyListener(new View.OnKeyListener() { 
      @Override 
      public boolean onKey(View v, int keyCode, KeyEvent event) { 
       if(event.getAction() == KeyEvent.ACTION_DOWN) 
        return true; 
       String strippedAmount = ed.getText().toString().replace(",", ""); 
       if(keyCode == KeyEvent.KEYCODE_DEL){ 
        //delete pressed, strip number of comas and then delete least significant digit. 
        strippedAmount = strippedAmount.substring(0, strippedAmount.length() - 1); 
        int amountNumeral = 0; 
        try{ 
         amountNumeral = Integer.parseInt(strippedAmount); 
        } catch(NumberFormatException e){ 
        } 
        myObject.amount = amountNumeral; 
        isUserInput = false; 
        setFormattedAmount(amountNumeral,ed.getId()); 
       }else if(keyCode == KeyEvent.KEYCODE_ENTER){ 
        //enter pressed, save edits and resign keyboard 
        int amountNumeral = 0; 
        try{ 
         amountNumeral = Integer.parseInt(strippedAmount); 
        } catch(NumberFormatException e){ 
        } 
        myObject.amount = amountNumeral; 
        isUserInput = false; 
        setFormattedAmount(myObject.amount,ed.getId()); 
        //save edits 
        save(); 
        //resign keyboard.. 
        InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 
        in.hideSoftInputFromWindow(AppHome.this.getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS); 
       } 
       return true; 
      } 
     }); 

     TextWatcher inputTextWatcher = new TextWatcher() { 
      public void afterTextChanged(Editable s) { 
       if(isUserInput == false){ 
        //textWatcher is recursive. When editText value is changed from code textWatcher callback gets called. So this variable acts as a flag which tells whether change is user generated or not..Possibly buggy code..:(
        isUserInput = true; 
        return; 
       } 
       String strippedAmount = ed.getText().toString().replace(",", ""); 
       int amountNumeral = 0; 
       try{ 
        amountNumeral = Integer.parseInt(strippedAmount); 
       } catch(NumberFormatException e){ 
       } 
       isUserInput = false; 
       setFormattedAmount(amountNumeral,ed.getId()); 
      } 

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

     ed.addTextChangedListener(inputTextWatcher); 
    }//end of onCreate... 

    public void setFormattedAmount(Integer amount, Integer inputBoxId){ 
     double amountValue = 0; 
     String textString =null; 
     TextView amountInputBox = (TextView) findViewById(inputBoxId); 

     amountValue = Double.parseDouble(Integer.toString(amount)); 
     textString = amountFormatter.format(amountValue).toString(); 
     amountInputBox.setText(textString); 
    } 
} 

Я знаю, что это большой вопрос, но я работаю над этой же проблемой в течение 2 дней. Я новичок в андроиде и все еще не могу поверить, что нет простого способа обрабатывать данные TextEdit на лету (я делал то же самое на iphone с легкостью). Спасибо всем

EDIT: после использования входного фильтра

InputFilter filter = new InputFilter() { 
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { 
      String strippedAmount = dest.toString() + source; 
      strippedAmount = strippedAmount.replace(",", ""); 

     int amountNumeral = 0; 
     try{ 
      amountNumeral = Integer.parseInt(strippedAmount); 
     } catch(NumberFormatException e){ 
     }   
      return amountFormatter.format(amountNumeral).toString(); 
    } 
}; 

ed.setFilters(new InputFilter[]{filter}); 

Когда приложение начинает Ставлю 1,234 на EditText

myObject.amount = 1234; 
ed.setText(amountFormatter.format(myObject.amount).toString()); 

Затем, когда пользователь нажимает на EditText, клавиатура выскакивает, и пользователь вводит цифру 6

Я получаю: 61234 Я хочу:12346

ответ

8

Ну, после большого удара головой я нашел работу вокруг проблемы с курсором. Я не знаю, правильно ли она у, но я получил это работает ..

TextWatcher inputTextWatcher = new TextWatcher() { 
     public void afterTextChanged(Editable s) { 
      if(isUserInput == false){ 
       //textWatcher is recursive. When editText value is changed from code textWatcher callback gets called. So this variable acts as a flag which tells whether change is user generated or not..Possibly buggy code..:(
       isUserInput = true; 
       ed.setSelection(ed.getText().length()); 
       return; 
      } 
      String strippedAmount = ed.getText().toString().replace(",", ""); 
      int amountNumeral = 0; 
      try{ 
       amountNumeral = Integer.parseInt(strippedAmount); 
      } catch(NumberFormatException e){ 
      } 
      isUserInput = false; 
      setFormattedAmount(amountNumeral,ed.getId()); 
     } 

     public void beforeTextChanged(CharSequence s, int start, int count, int after){ 
     } 
     public void onTextChanged(CharSequence s, int start, int before, int count) { 
     } 
    }; 
ed.addTextChangedListener(inputTextWatcher); 


ed.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      int length   = ed.getText().length(); 
      ed.setCursorVisible(true); 
      ed.setSelection(length); 
     } 
    }); 

ed.setOnKeyListener(new View.OnKeyListener() { 
    @Override 
    public boolean onKey(View v, int keyCode, KeyEvent event) { 
      if(event.getAction() == KeyEvent.ACTION_UP) 
       return true; 
      String strippedAmount = ed.getText().toString().replace(",", ""); 
      if(keyCode == KeyEvent.KEYCODE_DEL){ 
       //delete pressed, strip number of comas and then delete least significant digit. 
       strippedAmount = strippedAmount.substring(0, strippedAmount.length() - 1); 
       int amountNumeral = 0; 
       try{ 
        amountNumeral = Integer.parseInt(strippedAmount); 
       } catch(NumberFormatException e){ 
       } 
       isUserInput = false; 
       setFormattedAmount(amountNumeral,ed.getId()); 
       return true; 
      }else if(keyCode == KeyEvent.KEYCODE_ENTER){ 
       //enter pressed, save edits and resign keyboard 
       int amountNumeral = 0; 
       try{ 
        amountNumeral = Integer.parseInt(strippedAmount); 
       } catch(NumberFormatException e){ 
       } 
       isUserInput = false; 
       setFormattedAmount(amountNumeral,ed.getId()); 
       //save edits 
       //resign keyboard.. 
       InputMethodManager in = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 
       in.hideSoftInputFromWindow(AppHome.this.getCurrentFocus().getWindowToken(),InputMethodManager.HIDE_NOT_ALWAYS); 
       return true; 
      } 
      return false; 
    } 
}); 

То, что я сделал это на OnClick() из EditText, я насильно поместить курсор в конце текущего текста EditText, и я сделал то же самое, когда пользователь нажмите любую цифру. Надеюсь, это поможет кому-то ... Спасибо всем, кто пытался помочь.

+0

Downvoter, пожалуйста, учтите, что комментарий – Krishnabhadra

4

Для Маске ввода, вы можете создать подкласс InputFilter

Ниже приведен пример InputFilter подкласс, который капитализирует все строчные буквы:

/** 
    * This filter will capitalize all the lower case letters that are added 
    * through edits. 
    */ 
    public static class AllCaps implements InputFilter { 
     public CharSequence filter(CharSequence source, int start, int end, 
            Spanned dest, int dstart, int dend) { 
      for (int i = start; i < end; i++) { 
       if (Character.isLowerCase(source.charAt(i))) { 
        char[] v = new char[end - start]; 
        TextUtils.getChars(source, start, end, v, 0); 
        String s = new String(v).toUpperCase(); 

        if (source instanceof Spanned) { 
         SpannableString sp = new SpannableString(s); 
         TextUtils.copySpansFrom((Spanned) source, 
               start, end, null, sp, 0); 
         return sp; 
        } else { 
         return s; 
        } 
       } 
      } 

      return null; // keep original 
     } 
    } 

Приведенный выше код берется из Android's implementation of InputFilter

+0

Ну InputFilter, это ново для меня me..let бродить вокруг немного с this..Thanks Сарвар ... придет назад к вам .. – Krishnabhadra

+0

Я получаю InputFilter для работы. Но все же, когда я ввожу любое число, оно добавляется с исходным значением, присутствующим в текстовом поле. – Krishnabhadra

+0

@ Krishnabhadra: разместите свой код InputFilter. Кроме того, опубликуйте ввод, ваш ожидаемый результат и результат, который вы получаете (дайте в аренде один реальный сценарий) –

1

После нескольких часов работы я сделал маску ввода телефона. Для начала, после ввода «123456» он преобразует его в «+1 (234) 56». После удаления любого символа из любой позиции курсор перемещается в нужное положение, а не в начало или конец.

В деятельности:

etPhone.addTextChangedListener(new PhoneWatcher(etPhone)); 

В классе:

private class PhoneWatcher implements TextWatcher { 
    private static final String PHONE_MASK = "+# (###) ###-##-##"; 
    private final char[] PHONE_MASK_ARRAY = PHONE_MASK.toCharArray(); 

    private boolean isInTextChanged; 
    private boolean isInAfterTextChanged; 
    private EditText editText; 
    private int shiftCursor; 
    private String text; 
    private int cursor; 

    public PhoneWatcher(EditText editText) { 
     super(); 
     this.editText = editText; 
     isInTextChanged = false; 
     isInAfterTextChanged = false; 
    } 

    @Override 
    public synchronized void beforeTextChanged(CharSequence s, int start, int count, int after) { 
     shiftCursor = after - count; 
    } 

    @Override 
    public synchronized void onTextChanged(CharSequence s, int start, int before, int count) { 
     if (!isInTextChanged) { 
      isInTextChanged = true; 

      StringBuilder sb = new StringBuilder(); 
      for (int i = 0; i < s.length(); i++) { 
       char symbol = s.charAt(i); 
       if (symbol >= '0' && symbol <= '9') 
        sb.append(symbol); 
      } 
      String digits = sb.toString(); 

      sb.setLength(0); 
      int j = 0; 
      for (int i = 0; i < digits.length(); i++) { 
       char digit = digits.charAt(i); 
       while (j < PHONE_MASK_ARRAY.length) { 
        if (PHONE_MASK_ARRAY[j] == '#') { 
         sb.append(digit); 
         j++; 
         break; 
        } else { 
         sb.append(PHONE_MASK_ARRAY[j]); 
         j++; 
        } 
       } 
      } 

      cursor = editText.getSelectionStart(); 
      text = sb.toString(); 

      if (shiftCursor > 0) { 
       if (cursor > text.length()) 
        cursor = text.length(); 
       else { 
        while (cursor < PHONE_MASK_ARRAY.length && PHONE_MASK_ARRAY[cursor - 1] != '#') { 
         cursor++; 
        } 
       } 
      } else if (shiftCursor < 0) { 
       while (cursor > 0 && PHONE_MASK_ARRAY[cursor - 1] != '#') { 
        cursor--; 
       } 
      } 
     } 
    } 

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

      editText.setText(text); 
      editText.setSelection(cursor); 

      isInTextChanged = false; 
      isInAfterTextChanged = false; 
     } 
    } 
} 
Смежные вопросы