【问题标题】:android EditText ,keyboard textWatcher problemandroid EditText ,keyboard textWatcher 问题
【发布时间】:2011-08-04 11:00:01
【问题描述】:

我正在开发一个 android 应用程序,并且我有一个 EditText,用户可以在其中输入数字。我想使用不同的货币格式(比如##、##、###)来格式化数字,并且我想即时进行,即当用户输入每个数字时(而不是按下输入时)。我四处搜索,发现了TextWatcher,我首先发现它很有希望,但结果证明这绝对是一种痛苦。我正在一台只有软键盘的 HTC Desire 手机上调试我的代码。

现在我想在用户按下数字(0 到 9)、del(退格)键和 enter 键时获得回调。从我的测试中我发现了这些(至少在我的手机上)

1) 调用editText onKeyListener 当用户按 del 或 enter 键时。 当用户按下回车键时,onKey 一次输入调用两次函数 (我相信这是 ACTION_UP 和 ACTION_DOWN)。当用户按下 del 时, onKey 被调用一次(仅适用于 ACTION_DOWN) 我不知道为什么。 用户时永远不会调用 onKey 按下任何数字(0 到 9),这也是我 无法理解。

2) TextWatchers 3个回调函数 被称为(在TextChanged之前, onTextChanged, afterTextChanged) 每当用户按下任何数字(0 到 9) 键。所以我想通过使用 TextWatcher 和 onKeyListener 在一起 我可以得到我需要的所有回调。

现在我的问题是这些..

1) 首先在我的 HTC 软键盘那里 是一个键(带有 向下箭头),当我点击它时 键盘辞职不给 任何回调。我还是不敢相信 android让用户编辑字段 并辞职不让程序 处理(保存)编辑。现在我的 editText 显示一个值,而我的 对象有另一个值(我正在保存 用户在输入时进行编辑,并处理回 通过重置按下键盘 editText 值与中的值 对象,但我对此没有答案 键盘向下键)。

2) 二、我要格式化数字 用户输入新数字后。说 我已经有 123 在 editText 和 用户输入按下 4,我想要我的 editText 显示 1,234。我吃饱了 onTextChanged() 和 afterTextChanged() 我可以格式化 号码并将其放回 任何这些回调中的editText。 我应该使用哪一个?哪一个是 最佳实践?

3) 第三个是最关键的 问题。当应用程序启动时,我把 editText 中的当前对象值。 假设我在 onResume() 上放了 123,当 用户输入一个数字(比如 4)我想要它 是 1234。但在我的 onTextChanged 回调我得到的是4123。当 我再按一个键(比如 5) 我是 得到 45123。所以对于用户输入 editText 光标指向末尾 文本。但是当值由 手,editText 光标似乎不是 更新。我相信我必须做 textWatcher 回调中的某些内容,但是 我不知道我该怎么办。

我在下面发布我的代码。

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 天。我是 android 新手,仍然无法相信没有简单的方法可以即时处理 textEdit 数据(我在 iphone 上轻松地做了同样的事情)。谢谢大家

编辑:使用输入过滤器后

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

【问题讨论】:

    标签: android android-edittext formatter textwatcher


    【解决方案1】:

    好吧,经过多次头部撞击,我找到了解决光标位置问题的方法..我不知道这是否是正确的方法,但我得到了它的工作..

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

    我所做的是在editText的onClick()上,我强行将光标放在当前EditText文本的末尾,当用户按下任何数字时我也做了同样的事情。希望它对某人有所帮助..感谢所有试图提供帮助的人。

    【讨论】:

      【解决方案2】:

      对于 Masked 输入,您可以继承 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

      【讨论】:

      • 好吧 InputFilter,这对我来说是新的..让我用这个漫游一点..谢谢 Sarwar...会回来找你的..
      • 我正在让 InputFilter 工作。但是当我输入任何数字时,它仍然会在文本字段中添加原始值。
      • @Krishnabhadra:发布您的 InputFilter 代码。另外,发布输入,您的预期输出和您得到的输出(至少给出一个真实场景)
      • 我用输入过滤器四处寻找并理解过滤器返回的字符串只是放置在editText上的当前光标位置,将剩余的文本向右移动。我的问题是我希望光标指向editText中可用文本的结束位置,而不是开始或中间。
      • 嗯,好像不是输入过滤器或 textWatcher 的问题。我刚刚注释了 inputfilter 代码、textWatcher 代码、onKeyListener 代码并运行了程序。在 onResume() 的 editText 上放 1,234,然后从键盘输入 5,我得到的是 1,5234
      【解决方案3】:

      经过几个小时的工作,我做了一个电话输入掩码。 例如,在输入“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;
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-08
        • 2012-11-01
        • 2021-04-17
        • 1970-01-01
        相关资源
        最近更新 更多