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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12542211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:55:45  来源:igfitidea点击:

How to format number in android EditText after realtime editing

androidandroid-edittextnumber-formatting

提问by Asiimwe

I have an EditText in which the user should input a number including decimals and i want a thousand separator automatically added onto the input number I tried a couple of other methods but some do not allow floating point numbers so i came up with this code which works well only that the string input is not being edited in realtime to one with possible thousand separators and the errors seem to stem from the s.replace();

我有一个 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));
        }
    }
};

回答by Asiimwe

This Class solves the problem, allows decimal input and adds the thousand separators.

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

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

}

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

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

回答by estebanuri

Unfortunately the code did not work as it is in the answer.

不幸的是,代码在答案中不起作用。

It has two problems:

它有两个问题:

  1. It does not work if the phone locale configuration uses "," as a decimal separator.
  2. It does not work if the number has trailing zeros in the decimal part. Example 1.01.
  1. 如果电话区域设置使用“,”作为小数点分隔符,则它不起作用。
  2. 如果数字在小数部分有尾随零,则不起作用。例 1.01。

I went crazy to fix it. Finally I came to this code that worked well on my cell phone:

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

NumberTextWatcher.java

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("
    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);
", "" + 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); } }

and then to use it simply to do:

然后简单地使用它来做:

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

回答by Lucifer

You need to use DecimalFormatclass with DecimalFormatSymbolsclass, check the out following method,

您需要将DecimalFormat类与DecimalFormatSymbols类一起使用,请查看以下方法,

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

回答by Makwana Mehul

you can use kotlin extensions function like this...

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

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


}

回答by Ak.Ha

  input_text_rate.addTextChangedListener(new MyNumberWatcher_3Digit(input_text_rate));

// oncreate activity

// oncreate 活动

##代码##