How to Automatically add thousand separators as number is input in EditText

后端 未结 13 1956
花落未央
花落未央 2020-11-27 05:21

Im creating a convertor application, I want to set the EditText so that when the user is inputting the number to be converted, a thousand separator (,) should be added autom

相关标签:
13条回答
  • 2020-11-27 05:34

    I know i am very late to the party but it may be very useful for future users. My answer is an extension of Shree Krishna's answer.

    Improvements:

    1. Thousands separators and Decimal markers are locale aware i.e. they are used accordingly to the Locale of the device.
    2. The cursor position doesn't change after deleting or adding elements in the middle also (In his answer cursor was reset to the end).
    3. The overall quality of the code has been improved specially the getDecimalFormattedString method.

    Code:

        import android.text.Editable;
        import android.text.TextWatcher;
        import android.widget.EditText;
    
        import java.text.DecimalFormat;
    
    
        /**
         * Created by srv_twry on 4/12/17.
         * Source: https://stackoverflow.com/a/34265406/137744
         * The custom TextWatcher that automatically adds thousand separators in EditText.
         */
    
        public class ThousandSeparatorTextWatcher implements TextWatcher {
    
            private DecimalFormat df;
            private EditText editText;
            private static String thousandSeparator;
            private static String decimalMarker;
            private int cursorPosition;
    
            public ThousandSeparatorTextWatcher(EditText editText) {
                this.editText = editText;
                df = new DecimalFormat("#,###.##");
                df.setDecimalSeparatorAlwaysShown(true);
                thousandSeparator = Character.toString(df.getDecimalFormatSymbols().getGroupingSeparator());
                decimalMarker = Character.toString(df.getDecimalFormatSymbols().getDecimalSeparator());
            }
    
            @Override
            public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
                cursorPosition = editText.getText().toString().length() - editText.getSelectionStart();
            }
    
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
    
            @Override
            public void afterTextChanged(Editable s) {
                try {
                    editText.removeTextChangedListener(this);
                    String value = editText.getText().toString();
    
                    if (value != null && !value.equals("")) {
                        if (value.startsWith(decimalMarker)) {
                            String text = "0" + decimalMarker;
                            editText.setText(text);
                        }
                        if (value.startsWith("0") && !value.startsWith("0" + decimalMarker)) {
                            int index = 0;
                            while (index < value.length() && value.charAt(index) == '0') {
                                index++;
                            }
                            String newValue = Character.toString(value.charAt(0));
                            if (index != 0) {
                                newValue = value.charAt(0) + value.substring(index);
                            }
                            editText.setText(newValue);
                        }
                        String str = editText.getText().toString().replaceAll(thousandSeparator, "");
                        if (!value.equals("")) {
                            editText.setText(getDecimalFormattedString(str));
                        }
                        editText.setSelection(editText.getText().toString().length());
                    }
    
                    //setting the cursor back to where it was
                    editText.setSelection(editText.getText().toString().length() - cursorPosition);
                    editText.addTextChangedListener(this);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    editText.addTextChangedListener(this);
                }
            }
    
            private static String getDecimalFormattedString(String value) {
    
                String[] splitValue = value.split("\\.");
                String beforeDecimal = value;
                String afterDecimal = null;
                String finalResult = "";
    
                if (splitValue.length == 2) {
                    beforeDecimal = splitValue[0];
                    afterDecimal = splitValue[1];
                }
    
                int count = 0;
                for (int i = beforeDecimal.length() - 1; i >= 0 ; i--) {
                    finalResult = beforeDecimal.charAt(i) + finalResult;
                    count++;
                    if (count == 3 && i > 0) {
                        finalResult = thousandSeparator + finalResult;
                        count = 0;
                    }
                }
    
                if (afterDecimal != null) {
                    finalResult = finalResult + decimalMarker + afterDecimal;
                }
    
                return finalResult;
            }
    
            /*
            * Returns the string after removing all the thousands separators.
            * */
            public static String getOriginalString(String string) {
                return string.replace(thousandSeparator,"");
            }
        }
    
    0 讨论(0)
  • 2020-11-27 05:37

    Here i have tested my application code. text-watcher how to add comma in currency thousand, lake currency.

     private TextWatcher textWatcherAmount = 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) {
                String initial = s.toString();
    
                if (inputEdtHawalaRate == null) return;
    
                if (!TextUtils.isEmpty(initial)) {
    
                    initial = initial.replace(",", "");
    
                    NumberFormat formatter = new DecimalFormat("##,##,###");
    
                    inputEdtHawalaRate.removeTextChangedListener(this);
    
                    double myNumber = Double.parseDouble(initial);
                    String processed = formatter.format(myNumber);
    
                    //Assign processed text
                    inputEdtHawalaRate.setText(processed);
    
                    try {
                        inputEdtHawalaRate.setSelection(processed.length());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
    
                    //Give back the listener
                    inputEdtHawalaRate.addTextChangedListener(this);
    
                }
    
            }
    
            @Override
            public void afterTextChanged(Editable s) {
    
            }
        };
    
    
     if (inputEdtHawalaRate != null) {
                inputEdtHawalaRate.addTextChangedListener(textWatcherAmount);
            } 
    

    // getting amount on double type varaible (On textwatcher editetxt value get).

    String amount = Objects.requireNonNull(inputEdtHawalaRate.getText()).toString().trim();
    double hawalaAmount = 0.0;
    
     String[] a = amount.split(",");
                finalAmount = TextUtils.join("", a);
                hawalaAmount = Double.parseDouble(finalAmount);
    
    0 讨论(0)
  • 2020-11-27 05:40
      public static String doubleToStringNoDecimal(double d) {
            DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);;
            formatter .applyPattern("#,###");
            return formatter.format(d);
        }
    
    0 讨论(0)
  • 2020-11-27 05:40

    You can use this method:

    myEditText.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) {
    
                        String input = s.toString();
    
                        if (!input.isEmpty()) {
    
                            input = input.replace(",", "");
    
                            DecimalFormat format = new DecimalFormat("#,###,###");
                            String newPrice = format.format(Double.parseDouble(input));
    
    
                            myEditText.removeTextChangedListener(this); //To Prevent from Infinite Loop
    
                            myEditText.setText(newPrice);
                            myEditText.setSelection(newPrice.length()); //Move Cursor to end of String
    
                            myEditText.addTextChangedListener(this);
                        }
    
                    }
    
                    @Override
                    public void afterTextChanged(final Editable s) {
                    }
                });
    

    And to get original text use this:

    String input = myEditText.getText().toString();
    input = input.replace(",", "");
    
    0 讨论(0)
  • 2020-11-27 05:40

    you can use this code in many ways in your program, you give it a string and it separate each three from right and place space there.

    private String Spacer(String number){
        StringBuilder strB = new StringBuilder();
        strB.append(number);
        int Three = 0;
    
        for(int i=number.length();i>0;i--){
            Three++;
            if(Three == 3){
                strB.insert(i-1, " ");
                Three = 0;
            }
        }
        return strB.toString();
    }// end Spacer()
    

    u can change it a bit and use it ontextchangelistener. good luck

    0 讨论(0)
  • 2020-11-27 05:45

    This solution has some advantage over other answers. For example, it keeps the user's cursor position even if they edit the beginning or middle of the number. Other solutions always jump the cursor to the end of the number. It handles decimals and whole numbers, as well as locales that use characters other than . for the decimal separator and , for the thousands grouping separator.

    class SeparateThousands(val groupingSeparator: String, val decimalSeparator: String) : TextWatcher {
    
        private var busy = false
    
        override fun afterTextChanged(s: Editable?) {
            if (s != null && !busy) {
                busy = true
    
                var place = 0
    
                val decimalPointIndex = s.indexOf(decimalSeparator)
                var i = if (decimalPointIndex == -1) {
                    s.length - 1
                } else {
                    decimalPointIndex - 1
                }
                while (i >= 0) {
                    val c = s[i]
                    if (c == groupingSeparator[0] ) {
                        s.delete(i, i + 1)
                    } else {
                        if (place % 3 == 0 && place != 0) {
                            // insert a comma to the left of every 3rd digit (counting from right to
                            // left) unless it's the leftmost digit
                            s.insert(i + 1, groupingSeparator)
                        }
                        place++
                    }
                    i--
                }
    
                busy = false
            }
        }
    
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }
    
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }
    }
    

    Then in xml:

      <EditText
        android:id="@+id/myNumberField"
        android:digits=",.0123456789"
        android:inputType="numberDecimal"
        .../>
    

    And finally register the watcher:

    findViewById(R.id.myNumberField).addTextChangedListener(
        SeparateThousands(groupingSeparator, decimalSeparator))
    

    To handle . vs , in different locales use groupingSeparator and decimalSeparator, which can come from DecimalFormatSymbols or localized strings.

    0 讨论(0)
提交回复
热议问题