实时编辑后如何在android EditText中设置数字格式

实时编辑后如何在android EditText中设置数字格式,android,android-edittext,number-formatting,Android,Android Edittext,Number Formatting,我有一个EditText,用户应该在其中输入一个数字,包括小数,我希望在输入数字上自动添加1000个分隔符。我尝试了一些其他方法,但有些方法不允许使用浮点数,因此我提出了这段代码,它很好地工作,只是字符串输入没有被实时编辑为1可能的千个分隔符和错误似乎源于s.replace() am2=newtextWatcher(){ 更改前文本之前的公共void(字符序列s、int start、int count、int after){ } public void onTextChanged(字符序列,in

我有一个EditText,用户应该在其中输入一个数字,包括小数,我希望在输入数字上自动添加1000个分隔符。我尝试了一些其他方法,但有些方法不允许使用浮点数,因此我提出了这段代码,它很好地工作,只是字符串输入没有被实时编辑为1可能的千个分隔符和错误似乎源于s.replace()

am2=newtextWatcher(){
更改前文本之前的公共void(字符序列s、int start、int count、int after){
}
public void onTextChanged(字符序列,int start,int before,int count){}
公共无效后文本已更改(可编辑){
如果(s.toString().equals(“”){
金额.setText(“”);
数值=0;
}否则{
StringBuffer strBuff=新的StringBuffer();
字符c;
for(int i=0;i
您需要将
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);
}

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

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

}
公共类NumberTextWatcher实现TextWatcher{
专用分码格式df;
私有决策格式dfnd;
私有布尔部分;
私人编辑;
公用号码ExtWatcher(编辑文本et)
{
df=新的十进制格式(“#,###.##”);
df.setDecimalSeparatorAlwaysShown(真);
dfnd=新的十进制格式(“#,####”);
this.et=et;
hasstatilpart=false;
}
@抑制警告(“未使用”)
私有静态最终字符串标记=“NumberTextWatcher”;
公共无效后文本已更改(可编辑)
{
et.removeTextChangedListener(此);
试一试{
内伊尼伦,恩德伦;
inilen=et.getText().length();
String v=s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()),“”);
数字n=df.parse(v);
int cp=et.getSelectionStart();
if(hasstatilpart){
et.setText(df.format(n));
}否则{
et.setText(dfnd.format(n));
}
endlen=et.getText().length();
int sel=(cp+(endlen-inilen));

如果(sel>0&&sel很不幸,代码没有像答案中那样工作

它有两个问题:

  • 如果电话区域设置配置使用“,”作为十进制分隔符,则此选项不起作用
  • 如果数字的小数部分有尾随的零,则不起作用。示例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);
    
    
        }
    
    }
    

    您可以像这样使用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()
    

    我在Kotlin中使用这种方式进行对话框

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

    它不工作..EditText更改为新字符串的部分仍有错误separators@PaulAsiimweTumwesigye我已经完全测试过,
    System.out.println(formatAmount(1234))
    将给出输出1234谢谢你是的,我用System.out.println尝试了它,它输出了格式化的double,我的问题是,在我的android editText中,数字没有改变,只是在试图改变它时出错。@PaulasimWetumWesigye,StackOverflow error,对,是的,我创建了一个演示应用程序,得到了相同的结果,等等,我我会返回解决方案。您必须删除TextWatcher进行编辑,然后再添加它。如果我希望用户能够像这样输入数字:“1234.05”
    df=new DecimalFormat(“#,#,##.###”)
    此格式不允许逗号后加零,但如果我将其更改为
    df=new DecimalFormat(“#,#0”)
    它会在逗号后自动添加零。好吧,你可以添加另一个状态,比如“IsFractalPartThere”,然后用
    dfdot=new DecimalFormat(“#,####.”)解析它;
    但是如果你需要更高的精度“100.000005”,你会怎么做呢?如何将数字设置为1.000、1.000.000或1.000.000.000?没有通用格式可以添加千个分隔符,但保留小数不变吗?它在第15个字母后添加了000个输入。发生了什么事?这段代码很有效,但如果人们想理解它,而不是像猴子一样复制粘贴它,那就太糟糕了。变量名,如v、n、cp不是优秀程序员的标志。您可以使用此链接。当您需要数字格式的货币符号时,此链接非常有用。只需在fun EditText.text()=this.text.toString()上更改为fun EditText.text(输入:String)=GetCommalesNumber(this.text.toString())所以,当您想要在任何位置获取文本时,它将返回整数,而不进行格式化
    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');
        }
    
    
    }
    
      input_text_rate.addTextChangedListener(new MyNumberWatcher_3Digit(input_text_rate));
    
    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)
            }
        }