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

后端 未结 13 1957
花落未央
花落未央 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:46

    I just wanted comma to be placed and this is working for me:

    String.format("%,.2f", myValue);
    
    0 讨论(0)
  • 2020-11-27 05:49

    Solved The Issue Finally

    Even-though It is too late answer. I've researched much to accomplish the task To get the proper result but could not. So I finally solved the issue we were searching and provided this answer to the google searchers for saving their times on searching.

    Fetures of the following codes

    1. Puts thousand separator in EditText as it's text changes.

    2. adds 0. Automatically when pressed period (.) At First.

    3. Ignores 0 input at Beginning.

    Just copy the following Class named

    NumberTextWatcherForThousand which implements TextWatcher

    import android.text.Editable;
    import android.text.TextWatcher;
    import android.widget.EditText;
    import java.util.StringTokenizer;
    
    /**
     * Created by skb on 12/14/2015.
     */
    public class NumberTextWatcherForThousand implements TextWatcher {
    
        EditText editText;
    
    
        public NumberTextWatcherForThousand(EditText editText) {
            this.editText = editText;
    
    
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
    
        }
    
        @Override
        public void afterTextChanged(Editable s) {
            try
            {
                editText.removeTextChangedListener(this);
                String value = editText.getText().toString();
    
    
                if (value != null && !value.equals(""))
                {
    
                    if(value.startsWith(".")){
                        editText.setText("0.");
                    }
                    if(value.startsWith("0") && !value.startsWith("0.")){
                        editText.setText("");
    
                    }
    
    
                    String str = editText.getText().toString().replaceAll(",", "");
                    if (!value.equals(""))
                    editText.setText(getDecimalFormattedString(str));
                    editText.setSelection(editText.getText().toString().length());
                }
                editText.addTextChangedListener(this);
                return;
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
                editText.addTextChangedListener(this);
            }
    
        }
    
        public static String getDecimalFormattedString(String value)
        {
            StringTokenizer lst = new StringTokenizer(value, ".");
            String str1 = value;
            String str2 = "";
            if (lst.countTokens() > 1)
            {
                str1 = lst.nextToken();
                str2 = lst.nextToken();
            }
            String str3 = "";
            int i = 0;
            int j = -1 + str1.length();
            if (str1.charAt( -1 + str1.length()) == '.')
            {
                j--;
                str3 = ".";
            }
            for (int k = j;; k--)
            {
                if (k < 0)
                {
                    if (str2.length() > 0)
                        str3 = str3 + "." + str2;
                    return str3;
                }
                if (i == 3)
                {
                    str3 = "," + str3;
                    i = 0;
                }
                str3 = str1.charAt(k) + str3;
                i++;
            }
    
        }
    
        public static String trimCommaOfString(String string) {
    //        String returnString;
            if(string.contains(",")){
                return string.replace(",","");}
            else {
                return string;
            }
    
        }
    }
    

    Use This Class on your EditText as follows

    editText.addTextChangedListener(new NumberTextWatcherForThousand(editText));
    

    To get the input as plain Double Text

    Use the trimCommaOfString method of the same class like this

    NumberTextWatcherForThousand.trimCommaOfString(editText.getText().toString())
    

    Git

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

    Since i had the same problem i decided to find a solution to it

    Find my function below i hope it helps people finding solution

    securityDeposit.addTextChangedListener(new TextWatcher() {
    
                @Override
                public void onTextChanged(CharSequence s, int start,
                        int before, int count) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void beforeTextChanged(CharSequence s, int start,
                        int before, int count) {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    // TODO Auto-generated method stub
                    if (s.toString().trim().length() > 0) {
                        int rentValue = Integer.parseInt(s.toString()
                                .replaceAll(",", ""));
                        StringBuffer rentVal = new StringBuffer();
                        if (rentValue > 10000000) {
                            s.clear();
                            s.append("10,000,000");
                        } else {
    
                            if (s.length() == 4) {
                                char x[] = s.toString().toCharArray();
    
                                char y[] = new char[x.length + 1];
                                for (int z = 0; z < y.length; z++) {
    
                                    if (z == 1) {
                                        y[1] = ',';
    
                                    } else {
                                        if (z == 0)
                                            y[z] = x[z];
                                        else {
                                            y[z] = x[z - 1];
                                        }
                                    }
    
                                }
    
                                for (int z = 0; z < y.length; z++) {
                                    rentVal = rentVal.append(y[z]);
                                }
    
                                s.clear();
                                s.append(rentVal);
    
                            }
    
                        }
                    }
    
                }
            });
    
    0 讨论(0)
  • 2020-11-27 05:56

    Here is my ThousandNumberEditText class

    public class ThousandNumberEditText extends android.support.v7.widget.AppCompatEditText {
        // TODO: 14/09/2017 change it if you want 
        private static final int MAX_LENGTH = 20;
        private static final int MAX_DECIMAL = 3;
    
        public ThousandNumberEditText(Context context) {
            this(context, null);
        }
    
        public ThousandNumberEditText(Context context, AttributeSet attrs) {
            this(context, attrs, android.support.v7.appcompat.R.attr.editTextStyle);
        }
    
        public ThousandNumberEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            addTextChangedListener(new ThousandNumberTextWatcher(this));
            setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
            setFilters(new InputFilter[] { new InputFilter.LengthFilter(MAX_LENGTH) });
            setHint("0"); // TODO: 14/09/2017 change it if you want 
        }
    
        private static class ThousandNumberTextWatcher implements TextWatcher {
    
            private EditText mEditText;
    
            ThousandNumberTextWatcher(EditText editText) {
                mEditText = 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) {
                String originalString = editable.toString();
                String cleanString = originalString.replaceAll("[,]", "");
                if (cleanString.isEmpty()) {
                    return;
                }
                String formattedString = getFormatString(cleanString);
    
                mEditText.removeTextChangedListener(this);
                mEditText.setText(formattedString);
                mEditText.setSelection(mEditText.getText().length());
                mEditText.addTextChangedListener(this);
            }
    
            /**
             * Return the format string
             */
            private String getFormatString(String cleanString) {
                if (cleanString.contains(".")) {
                    return formatDecimal(cleanString);
                } else {
                    return formatInteger(cleanString);
                }
            }
    
            private String formatInteger(String str) {
                BigDecimal parsed = new BigDecimal(str);
                DecimalFormat formatter;
                formatter = new DecimalFormat("#,###");
                return formatter.format(parsed);
            }
    
            private String formatDecimal(String str) {
                if (str.equals(".")) {
                    return ".";
                }
                BigDecimal parsed = new BigDecimal(str);
                DecimalFormat formatter;
                formatter =
                        new DecimalFormat("#,###." + getDecimalPattern(str)); //example patter #,###.00
                return formatter.format(parsed);
            }
    
            /**
             * It will return suitable pattern for format decimal
             * For example: 10.2 -> return 0 | 10.23 -> return 00 | 10.235 -> return 000
             */
            private String getDecimalPattern(String str) {
                int decimalCount = str.length() - 1 - str.indexOf(".");
                StringBuilder decimalPattern = new StringBuilder();
                for (int i = 0; i < decimalCount && i < MAX_DECIMAL; i++) {
                    decimalPattern.append("0");
                }
                return decimalPattern.toString();
            }
        }
    }
    

    Using

    <.ThousandNumberEditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />
    
    0 讨论(0)
  • 2020-11-27 05:57

    You can use String.format() in a TextWatcher. The comma in the format specifier does the trick.

    This does not work for floating point input. And be careful not to set an infinite loop with the TextWatcher.

    public void afterTextChanged(Editable view) {
        String s = null;
        try {
            // The comma in the format specifier does the trick
            s = String.format("%,d", Long.parseLong(view.toString()));
        } catch (NumberFormatException e) {
        }
        // Set s back to the view after temporarily removing the text change listener
    }
    
    0 讨论(0)
  • 2020-11-27 05:58

    The answers here lack a method to handle actual user input, such as deleting characters or copying and pasting. This is an EditText field. If you want to add formatting in, you need to support editing that formatted value.

    This implementation still has a deficiency depending on your use case. I didn't care about decimal values and assumed I would only be handling whole numbers. There's enough of how to handle that on this page and how to handle actual internationalization that I'll leave that as an exercise to the reader. If you need to do that, it shouldn't be too difficult to add "." to the regular expression to keep the decimal; you'll just have to be careful to acknowledge the numeral string still has a non numerical character.

    This is designed to be used throughout multiple activities. New it once, give it your edit text and your data model and ignore it. The model binding can be removed if you don't need it.

    public class EditNumberFormatter implements TextWatcher {
    
        private EditText watched;
        private Object model;
        private Field field;
        private IEditNumberFormatterListener listener;
    
        private ActiveEdit activeEdit;
    
        /**
         * Binds an EditText to a data model field (Such as a room entity's public variable)
         * Whenever the edit text is changed, the text is formatted to the local numerical format.
         *
         * Handles copy/paste/backspace/select&delete/typing
         *
         * @param model An object with a public field to bind to
         * @param fieldName A field defined on the object
         * @param watched The edit text to watch for changes
         * @param listener Another object that wants to know after changes & formatting are done.
         */
        public EditNumberFormatter(Object model, String fieldName, EditText watched, IEditNumberFormatterListener listener) {
    
            this.model = model;
            this.watched = watched;
            this.listener = listener;
    
            try {
                field = model.getClass().getDeclaredField(fieldName);
            } catch(Exception e) { }
    
            watched.addTextChangedListener(this);
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            activeEdit = new ActiveEdit(s.toString(), start, count);
        }
    
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            activeEdit.recordChangedText(s.toString(),count);
        }
    
        @Override
        public void afterTextChanged(Editable s) {
            this.watched.removeTextChangedListener(this);
    
            activeEdit.processEdit(); // Override the user's edit of the formatted string with what the user intended to do to the numeral.
    
            watched.setText(activeEdit.getCurrentFormattedString());
            watched.setSelection(activeEdit.getCursorPosition());
            updateDataModel(activeEdit.getCurrentRawValue());
    
            listener.FormatUpdated(watched.getId(), activeEdit.getCurrentRawValue(), activeEdit.getCurrentFormattedString());
    
            this.watched.addTextChangedListener(this);
        }
    
        private void updateDataModel(int rawValue) {
            try {
                field.set(model, rawValue);
            } catch (IllegalAccessException e) { }
        }
    
        /**
         * Tracks the active editing of an EditText formatted for integer input
         */
        private class ActiveEdit {
    
            private String priorFormattedString;
            private String currentFormattedString;
            private String currentNumericalString;
            private int currentRawValue;
    
            private boolean removal;
            private boolean addition;
    
            private int changeStart;
            private int removedCount;
            private int additionCount;
    
            private int numeralCountBeforeSelection;
            private int numeralCountAdded;
            private int numeralCountRemoved;
    
            /**
             * Call in beforeEdit to begin recording changes
             *
             * @param beforeEdit string before edit began
             * @param start start position of edit
             * @param removed number of characters removed
             */
            public ActiveEdit(String beforeEdit, int start, int removed) {
                removal = (removed > 0);
    
                priorFormattedString = beforeEdit;
                changeStart = start;
                removedCount = removed;
    
                numeralCountBeforeSelection = countNumerals(priorFormattedString.substring(0, changeStart));
                numeralCountRemoved = countNumerals(priorFormattedString.substring(changeStart, changeStart + removedCount));
            }
    
            /**
             * Call in onTextChanged to record new text and how many characters were added after changeStart
             *
             * @param afterEdit new string after user input
             * @param added how many characters were added (same start position as before)
             */
            public void recordChangedText(String afterEdit, int added) {
                addition = (added > 0);
                additionCount = added;
                numeralCountAdded = countNumerals(afterEdit.substring(changeStart, changeStart + additionCount));
    
                currentNumericalString = afterEdit.replaceAll("[^0-9]", "");
            }
    
            /**
             * Re-process the edit for our particular formatting needs.
             */
            public void processEdit() {
                forceRemovalPastFormatting();
                finalizeEdit();
            }
    
            /**
             * @return Integer value of the field after an edit.
             */
            public int getCurrentRawValue() {
                return currentRawValue;
            }
    
            /**
             * @return Formatted number after an edit.
             */
            public String getCurrentFormattedString() {
                return currentFormattedString;
            }
    
            /**
             * @return Cursor position after an edit
             */
            public int getCursorPosition() {
                int numeralPosition = numeralCountBeforeSelection + numeralCountAdded;
                return positionAfterNumeralN(currentFormattedString,numeralPosition);
            }
    
            /**
             * If a user deletes a value, but no numerals are deleted, then delete the numeral proceeding
             * their cursor. Otherwise, we'll just add back the formatting character.
             *
             * Assumes formatting uses a single character and not multiple formatting characters in a row.
             */
            private void forceRemovalPastFormatting() {
                if (removal && (!addition) && (numeralCountRemoved == 0)) {
                    String before = currentNumericalString.substring(0, numeralCountBeforeSelection - 1);
                    String after = currentNumericalString.substring(numeralCountBeforeSelection);
    
                    currentNumericalString =  before + after;
                    numeralCountRemoved++;
                    numeralCountBeforeSelection--;
                }
            }
    
            /**
             * Determine the result of the edit, including new display value and raw value
             */
            private void finalizeEdit() {
                currentFormattedString = "";
                currentRawValue = 0;
                if (currentNumericalString.length() == 0) {
                    return; // There is no entry now.
                }
                try {
                    currentRawValue = Integer.parseInt(currentNumericalString);
                } catch (NumberFormatException nfe) {
                    abortEdit();  // Value is not an integer, return to previous state.
                    return;
                }
                currentFormattedString = String.format("%,d", currentRawValue);
            }
    
            /**
             * Current text, same as the old text.
             */
            private void abortEdit() {
                currentFormattedString = priorFormattedString;
                currentNumericalString = currentFormattedString.replaceAll("[^0-9]", "");
                numeralCountRemoved = 0;
                numeralCountAdded = 0;
                try {
                    currentRawValue = Integer.parseInt(currentNumericalString);
                } catch (Exception e) { currentRawValue = 0; }
            }
    
            /**
             * Determine how many numerical characters exist in a string
             * @param s
             * @return the number of numerical characters in the string
             */
            private int countNumerals(String s) {
                String newString = s.replaceAll("[^0-9]", "");
                return newString.length();
            }
    
            /**
             * Determine how to place a cursor after the Nth Numeral in a formatted string.
             * @param s - Formatted string
             * @param n - The position of the cursor should follow the "Nth" number in the string
             * @return the position of the nth character in a formatted string
             */
            private int positionAfterNumeralN(String s, int n) {
                int numeralsFound = 0;
    
                if (n == 0) {
                    return 0;
                }
    
                for (int i = 0; i < s.length(); i++) {
                    if(s.substring(i,i+1).matches("[0-9]")) {
                        if(++numeralsFound == n) {
                            return i + 1;
                        }
                    }
                }
                return s.length();
            }
        }
    }
    

    At a highlevel, what that does is:

    • Determine which numbers were actually in the string after it was edited
    • Process the edit to the numeral version of the string if the numbers weren't edited
    • Convert the numeral back to a formatted string
    • Determine, where the cursor should be based on where editing began and how much text was added

    It also nicely handles edge cases like completely deleted input, integer overflow and erroneous input.

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