Format EditText to currency with whole numbers

2019-04-11 13:16发布

问题:

All- I have a TextWatcher that formats an EditText to currency format:

private String current = "";
public void onTextChanged(CharSequence s, int start, int before, int count) {
    if(!s.toString().equals(current)){
        editText$.removeTextChangedListener(this);

       String cleanString = s.toString().replaceAll("[$,.]", "");

       double parsed = Double.parseDouble(cleanString);           
       String formated = NumberFormat.getCurrencyInstance().format((parsed/100));          

       current = formated;
       editText$.setText(formated);
       editText$.setSelection(formated.length());

       editText$.addTextChangedListener(this);
    }
}

This works great, the problem is that my EditText only needs whole numbers so I do not the user to be able to enter cents. So instead of 0.01 than 0.12 than 1.23 than 12.34, I want 1 than 12 than 123 than 1,234. How can I get rid of the decimal point but keep the commas? Thank you.

回答1:

If you don't mind removing the period and trailing zeroes, you could do this:

    mEditText.addTextChangedListener(new TextWatcher() {
        private String current = "";

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (!s.toString().equals(current)) {
                annualIncomeEntry.removeTextChangedListener(this);

                String cleanString = s.toString().replaceAll("[$,]", "");

                if (cleanString.length() > 0) {
                    double parsed = Double.parseDouble(cleanString);
                    NumberFormat formatter = NumberFormat.getCurrencyInstance();
                    formatter.setMaximumFractionDigits(0);
                    current = formatter.format(parsed);
                } else {
                    current = cleanString;
                }


                annualIncomeEntry.setText(current);
                annualIncomeEntry.setSelection(current.length());
                annualIncomeEntry.addTextChangedListener(this);
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }

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

This will set the number formatter's maximum fraction digits to zero, removing all trailing zeroes and the period. I also removed the division by 100 so that all entered numbers are integers.

Also make sure that your EditText's inputType is "number" or this will crash if the user tries to enter a non-numeric character.



回答2:

Hexar's answer was useful but it lacked error detection when the user deleted all the numbers or moved the cursor. I built on to his answer and an answer here to form a complete solution. It may not be best practice due to setting the EditText in the onTextChanged() method but it works.

    /* don't allow user to move cursor while entering price */
    mEditText.setMovementMethod(null);
    mEditText.addTextChangedListener(new TextWatcher() {
        private String current = "";
        NumberFormat formatter = NumberFormat.getCurrencyInstance();
        private double parsed;

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (!s.toString().equals(current)) {
                /* remove listener to prevent stack overflow from infinite loop */
                mEditText.removeTextChangedListener(this);
                String cleanString = s.toString().replaceAll("[$,]", "");

                try {
                    parsed = Double.parseDouble(cleanString);
                }
                catch(java.lang.NumberFormatException e) {
                    parsed = 0;
                }

                formatter.setMaximumFractionDigits(0);
                String formatted = formatter.format(parsed);

                current = formatted;
                mEditText.setText(formatted);

                /* add listener back */
                mEditText.addTextChangedListener(this);
                /* print a toast when limit is reached... see xml below. 
                 * this is for 6 chars */
                if (start == 7) {
                    Toast toast = Toast.makeText(getApplicationContext(), 
                        "Maximum Limit Reached", Toast.LENGTH_LONG);
                    toast.setGravity(Gravity.CENTER, 0, 0);
                    toast.show();
                }
            }
        }

A quick way to ensure the user doesn't enter invalid information is to edit the xml. For my program, a limit of 6 number characters was set.

        <!-- it says maxLength 8 but it's really 6 digits and a '$' and a ',' -->
        <EditText
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:inputType="number|textVisiblePassword"
            android:maxLength="8"
            android:digits="0123456789"
            android:id="@+id/mEditText"
            android:hint="Price"/>


回答3:

Why don't you format the amount using currencyFormat and then take out the .00 from the String.

private static final ThreadLocal<NumberFormat> currencyFormat = new ThreadLocal<NumberFormat>() {
        @Override
        protected NumberFormat initialValue() {
            return NumberFormat.getCurrencyInstance();
        }
    };

currencyFormat.get().format( < your_amount_here > )



回答4:

etProductCost.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (s.toString().length() == 1){
                //first number inserted.
                if (s.toString().equals(getString(R.string.currency_symbol))){
                    //if it is a currecy symbol
                    etProductCost.setText("");
                }else {
                    etProductCost.setText(getString(R.string.currency_symbol) + s.toString());
                    etProductCost.setSelection(s.toString().length());
                }
                return;
            }
            //set cursor position to last in edittext
            etProductCost.setSelection(s.toString().length());
        }

        @Override
        public void afterTextChanged(Editable s) {}
    });