【问题标题】:How to format number in android EditText after realtime editing实时编辑后如何在android EditText中格式化数字
【发布时间】:2012-09-14 13:34:44
【问题描述】:

我有一个 EditText,用户应该在其中输入一个包含小数的数字,我希望在输入数字上自动添加一个千位分隔符我尝试了其他几种方法,但有些方法不允许浮点数,所以我想出了这个仅在字符串输入没有被实时编辑为具有可能的千位分隔符的代码并且错误似乎源于 s.replace();

    am2 = new TextWatcher(){
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }
    public void onTextChanged(CharSequence s, int start, int before, int count) {}
    public void afterTextChanged(Editable s) {
        if (s.toString().equals("")) {
            amount.setText("");
            value = 0;
        }else{
            StringBuffer strBuff = new StringBuffer();
            char c;
            for (int i = 0; i < amount2.getText().toString().length() ; i++) {
                c = amount2.getText().toString().charAt(i);
                if (Character.isDigit(c)) {
                    strBuff.append(c);
                }
            }
            value = Double.parseDouble(strBuff.toString());
            reverse();
            NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
            ((DecimalFormat)nf2).applyPattern("###,###.#######");
            s.replace(0, s.length(), nf2.format(value));
        }
    }
};

【问题讨论】:

标签: android android-edittext number-formatting


【解决方案1】:

这个类解决了这个问题,允许十进制输入并添加千位分隔符。

    public class NumberTextWatcher implements TextWatcher {

    private DecimalFormat df;
    private DecimalFormat dfnd;
    private boolean hasFractionalPart;

    private EditText et;

    public NumberTextWatcher(EditText et)
    {
        df = new DecimalFormat("#,###.##");
        df.setDecimalSeparatorAlwaysShown(true);
        dfnd = new DecimalFormat("#,###");
        this.et = et;
        hasFractionalPart = false;
    }

    @SuppressWarnings("unused")
    private static final String TAG = "NumberTextWatcher";

    public void afterTextChanged(Editable s)
    {
        et.removeTextChangedListener(this);

        try {
            int inilen, endlen;
            inilen = et.getText().length();

            String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
            Number n = df.parse(v);
            int cp = et.getSelectionStart();
            if (hasFractionalPart) {
                et.setText(df.format(n));
            } else {
                et.setText(dfnd.format(n));
            }
            endlen = et.getText().length();
            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= et.getText().length()) {
                et.setSelection(sel);
            } else {
                // place cursor at the end?
                et.setSelection(et.getText().length() - 1);
            }
        } catch (NumberFormatException nfe) {
            // do nothing?
        } catch (ParseException e) {
            // do nothing?
        }

        et.addTextChangedListener(this);
    }

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

    public void onTextChanged(CharSequence s, int start, int before, int count)
    {
        if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
        {
            hasFractionalPart = true;
        } else {
            hasFractionalPart = false;
        }
    }

}

来源:http://blog.roshka.com/2012/08/android-edittext-with-number-format.html

【讨论】:

  • 如果我希望用户能够输入这样的数字:“1,234.05”怎么样? df = new DecimalFormat("#,###.##"); 这种格式不允许逗号后加零,但如果我将其更改为df = new DecimalFormat("#,###.0#");,它会在逗号后自动添加零。好吧,您可以添加另一个状态,例如“isFractionalPartThere”并使用dfdot = new DecimalFormat("#,###."); 解析它,但如果您需要允许更精确的“100.000005”,您将如何处理?
  • 如何使数字像 1.000 或 1.000.000 或 1.000.000.000 ?
  • 没有添加千位分隔符但保持小数不变的通用格式吗?
  • 在第 15 个字母后添加 000 输入。发生了什么??
  • 这段代码有效,但如果人们想理解它而不是像猴子一样复制粘贴,那真的很糟糕。 v、n、cp 等变量名并不是优秀程序员的标志
【解决方案2】:

不幸的是,代码没有像答案中那样工作。

它有两个问题:

  1. 如果电话语言环境配置使用“,”作为小数分隔符,它不起作用。
  2. 如果数字在小数部分有尾随零,则它不起作用。示例 1.01。

我疯狂地修复它。 最后我找到了在我的手机上运行良好的代码:

NumberTextWatcher.java

import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.util.Log;
import android.widget.EditText;

import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;


public class NumberTextWatcher
        implements TextWatcher {

    private static final String TAG = "NumberTextWatcher";

    private final int numDecimals;
    private String groupingSep;
    private String decimalSep;
    private boolean nonUsFormat;
    private DecimalFormat df;
    private DecimalFormat dfnd;
    private boolean hasFractionalPart;

    private EditText et;
    private String value;


    private String replicate(char ch, int n) {
        return new String(new char[n]).replace("\0", "" + ch);
    }

    public NumberTextWatcher(EditText et, Locale locale, int numDecimals) {

        et.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));
        this.numDecimals = numDecimals;
        DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);

        char gs = symbols.getGroupingSeparator();
        char ds = symbols.getDecimalSeparator();
        groupingSep = String.valueOf(gs);
        decimalSep = String.valueOf(ds);

        String patternInt = "#,###";
        dfnd = new DecimalFormat(patternInt, symbols);

        String patternDec = patternInt + "." + replicate('#', numDecimals);
        df = new DecimalFormat(patternDec, symbols);
        df.setDecimalSeparatorAlwaysShown(true);
        df.setRoundingMode(RoundingMode.DOWN);

        this.et = et;
        hasFractionalPart = false;

        nonUsFormat = !decimalSep.equals(".");
        value = null;

    }


    @Override
    public void afterTextChanged(Editable s) {
        Log.d(TAG, "afterTextChanged");
        et.removeTextChangedListener(this);

        try {
            int inilen, endlen;
            inilen = et.getText().length();

            String v = value.replace(groupingSep, "");

            Number n = df.parse(v);

            int cp = et.getSelectionStart();
            if (hasFractionalPart) {
                int decPos = v.indexOf(decimalSep) + 1;
                int decLen = v.length() - decPos;
                if (decLen > numDecimals) {
                    v = v.substring(0, decPos + numDecimals);
                }
                int trz = countTrailingZeros(v);

                StringBuilder fmt = new StringBuilder(df.format(n));
                while (trz-- > 0) {
                    fmt.append("0");
                }
                et.setText(fmt.toString());
            } else {
                et.setText(dfnd.format(n));
            }


            endlen = et.getText().length();
            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= et.getText().length()) {
                et.setSelection(sel);
            } else {
                // place cursor at the end?
                et.setSelection(et.getText().length() - 1);
            }


        } catch (NumberFormatException | ParseException nfe) {
            // do nothing?
        }


        et.addTextChangedListener(this);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        Log.d(TAG, "beforeTextChanged");
        value = et.getText().toString();
    }

    private int countTrailingZeros(String str) {
        int count = 0;

        for (int i = str.length() - 1; i >= 0; i--) {
            char ch = str.charAt(i);
            if ('0' == ch) {
                count++;
            } else {
                break;
            }
        }
        return count;
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        Log.d(TAG, "onTextChanged");

        String newValue = s.toString();
        String change = newValue.substring(start, start + count);
        String prefix = value.substring(0, start);
        String suffix = value.substring(start + before);

        if (".".equals(change) && nonUsFormat) {
            change = decimalSep;
        }

        value = prefix + change + suffix;
        hasFractionalPart = value.contains(decimalSep);

        Log.d(TAG, "VALUE: " + value);


    }

}

然后简单地用它来做:

    Locale locale = new Locale("es", "AR"); // For example Argentina
    int numDecs = 2; // Let's use 2 decimals
    TextWatcher tw = new NumberTextWatcher(myEditText, locale, numDecs);
    myEditText.addTextChangedListener(tw);

【讨论】:

    【解决方案3】:

    你需要使用DecimalFormat类和DecimalFormatSymbols类,看看下面的方法,

    public static String formatAmount(int num) 
    {
        DecimalFormat decimalFormat = new DecimalFormat();
        DecimalFormatSymbols decimalFormateSymbol = new DecimalFormatSymbols();
        decimalFormateSymbol.setGroupingSeparator(',');
        decimalFormat.setDecimalFormatSymbols(decimalFormateSymbol);
        return decimalFormat.format(num);
    }
    

    【讨论】:

    • 它不起作用.. 错误仍然出现在 EditText 更改为带有千位分隔符的新字符串的部分
    • @PaulAsiimweTumwesigye 我已经过全面测试,System.out.println ( formatAmount ( 1234 ) ); 将输出 1,234
    • 谢谢,是的,我已经尝试使用 System.out.println 并输出格式化的双精度,我的问题是在我的 android editText 中数字没有改变它只是在尝试改变时出错它。
    • @PaulAsiimweTumwesigye,StackOverflow 错误,对,是的,我创建了一个演示应用程序,并且得到了相同的结果,请稍等,我会返回解决方案。
    • 您必须删除 TextWatcher 进行编辑,然后重新添加。
    【解决方案4】:

    你可以像这样使用 kotlin 扩展功能...

    fun EditText.onCommaChange(input: (String) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
            if (!edit) {
                edit = true
                if (s.toString() != "₹") {
                    try {
                        val flNumber = getCommaLessNumber(s.toString()).toInt()
                        val fNumber = getFormattedAmount(flNumber)
                        setText(fNumber)
                        setSelection(text.length)
                        input(flNumber.toString())
                    } catch (e: NumberFormatException) {
                        Timber.e(e)
                    }
                } else {
                    setText("")
                    input("")
                }
                edit = false
            }
        }
    
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
    
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
    })}
    
    fun getCommaLessNumber(commaNumber: String): String {
    var number = commaNumber.replace("₹", "")
    number = number.replace(",".toRegex(), "")
    return number}
    
    fun getFormattedAmount(amount: Int): String {
    return "₹${String.format("%,d", amount)}"}
    
    fun EditText.text() = this.text.toString()
    

    【讨论】:

    • 当你想要一个数字格式的货币符号时这非常有用
    • 只需将上面 fun EditText.text() = this.text.toString() 更改为 fun EditText.text(input: String) = getCommaLessNumber(this.text.toString()) 所以,当你想要在任何地方获取文本,它将返回整数而不格式化
    【解决方案5】:
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.widget.EditText;
    import java.text.DecimalFormat;
    public class MyNumberWatcher_3Digit implements TextWatcher {
        private EditText editText;
        private int digit;
    
    
        public MyNumberWatcher_3Digit(EditText editText) {
            this.editText = editText;
    
        }
    
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
        }
    
        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
        }
    
        @Override
        public void afterTextChanged(Editable editable) {
            editText.removeTextChangedListener( this );
    
            String s = editText.getText().toString();
            s = s.replace( ",", "" ).replace( "٬", "" );
            s = replaceNonstandardDigits( s );
            if (s.length() > 0) {
                DecimalFormat sdd = new DecimalFormat( "#,###" );
                Double doubleNumber = Double.parseDouble( s );
    
                String format = sdd.format( doubleNumber );
                editText.setText( format );
                editText.setSelection( format.length() );
    
            }
            editText.addTextChangedListener( this );
        }
    
    
        static String replaceNonstandardDigits(String input) {
            if (input == null || input.isEmpty()) {
                return input;
            }
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < input.length(); i++) {
                char ch = input.charAt( i );
                if (isNonstandardDigit( ch )) {
                    int numericValue = Character.getNumericValue( ch );
                    if (numericValue >= 0) {
                        builder.append( numericValue );
                    }
                } else {
                    builder.append( ch );
                }
            }
            return builder.toString();
        }
    
        private static boolean isNonstandardDigit(char ch) {
            return Character.isDigit( ch ) && !(ch >= '0' && ch <= '9');
        }
    
    
    }
    

    // oncreate 活动

      input_text_rate.addTextChangedListener(new MyNumberWatcher_3Digit(input_text_rate));
    

    【讨论】:

      【解决方案6】:

      我在 Kotlin 中将这种方式用于 Dialog

      val et = dialog.findViewById(R.id.etNumber) as EditText
      et.addTextChangedListener(object : TextWatcher {
                      override fun afterTextChanged(s: Editable) {
      
                          et.removeTextChangedListener(this)
                          forChanged(et)
                          et.addTextChangedListener(this)
                      }
      
                      override fun beforeTextChanged(
                          s: CharSequence,
                          start: Int,
                          count: Int,
                          after: Int
                      ) {
      
                      }
      
                      override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
      
                      }
                  })
      

      然后写一个这样的方法:

      private fun forChanged(alpha: EditText) {
              val string = alpha.text.toString()
              val dec = DecimalFormat("#,###")
              if (!TextUtils.isEmpty(string)) {
                  val textWC = string.replace(",".toRegex(), "")
                  val number = textWC.toDouble()
                  alpha.setText(dec.format(number))
                  alpha.setSelection(dec.format(number).length)
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-16
        • 2012-02-19
        • 1970-01-01
        • 2018-09-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多