如何在EditText中输入自动添加千位分隔符作为数字

时间:2012-09-09 10:51:12

标签: android android-layout android-emulator android-edittext

我正在创建一个转换器应用程序,我想设置EditText,这样当用户输入要转换的数字时,一旦它增加3个数字,就应该实时自动添加一千个分隔符(,)。 ......千万,百万,亿等 当擦除到4以下时,数字会恢复正常。 有帮助吗? 谢谢。

14 个答案:

答案 0 :(得分:44)

最终解决了问题

即便 - 虽然答案太晚了。我已经研究了很多来完成任务以获得正确的结果,但却无法完成。所以我终于解决了我们正在搜索的问题,并向谷歌搜索者提供了这个答案,以节省搜索时间。

以下代码的确认

  1. 在文本发生变化时,在EditText中放置千位分隔符。

  2. 在按下句点(。)时自动添加0.

  3. 在Beginning忽略0输入。

  4. 只需复制以下内容即可 名为

    的类

    NumberTextWatcherForThousand 实施 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;
            }
    
        }
    }
    

    EditText上使用此课程如下

    editText.addTextChangedListener(new NumberTextWatcherForThousand(editText));
    

    将输入视为普通双文

    使用同一类的trimCommaOfString方法

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

    Git

答案 1 :(得分:35)

您可以在TextWatcher中使用String.format()格式说明符中的逗号可以解决问题。

这不适用于浮点输入。并注意不要使用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
}

答案 2 :(得分:24)

  public static String doubleToStringNoDecimal(double d) {
        DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);;
        formatter .applyPattern("#,###");
        return formatter.format(d);
    }

答案 3 :(得分:5)

sample app清楚地解构格式化数字。

要总结上述链接,请使用TextWatcher并使用afterTextChanged()方法格式EditText视图,并使用以下逻辑:

@Override
public void afterTextChanged(Editable s) {
    editText.removeTextChangedListener(this);

    try {
        String originalString = s.toString();

        Long longval;
        if (originalString.contains(",")) {
            originalString = originalString.replaceAll(",", "");
        }
        longval = Long.parseLong(originalString);

        DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
        formatter.applyPattern("#,###,###,###");
        String formattedString = formatter.format(longval);

        //setting text after format to EditText
        editText.setText(formattedString);
        editText.setSelection(editText.getText().length());
    } catch (NumberFormatException nfe) {
        nfe.printStackTrace();
    }

    editText.addTextChangedListener(this);
}

答案 4 :(得分:2)

此解决方案比其他答案有一些优势。例如,即使编辑了数字的开头或中间,它也会保持用户的光标位置。 其他解决方案始终将光标跳到数字的末尾。它处理小数和整数,以及使用除.以外的字符作为小数分隔符的区域设置,以及用于千位分组分隔符的,

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 == ',') {
                    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) {
    }
}

然后在xml:

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

最后注册观察者:

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

要处理。 vs,在不同的语言环境中使用groupingSeparator和decimalSeparator,它们可以来自DecimalFormatSymbols或本地化字符串。

答案 5 :(得分:2)

我知道我参加聚会很晚,但对未来的用户来说可能非常有用。我的回答是Shree Krishna答案的延伸。

改进:

  1. 数千个分隔符和十进制标记可识别区域设置,即它们相应地用于设备的subprocess.check_call("cp -rv ./src/CopyPasteIntoBuildDir/* ./build-root/src/", shell=True, executable="/bin/bash")
  2. 删除或添加中间的元素后,光标位置不会改变(在他的答案光标中重置为结尾)。
  3. 特别是Locale方法改进了代码的整体质量。
  4. 代码:

    getDecimalFormattedString

答案 6 :(得分:1)

你可以在你的程序中以多种方式使用这段代码,你给它一个字符串,它将每三个与右边分开,并在那里放置空间。

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

你可以稍微改变它并使用它ontextchangelistener。 祝你好运

答案 7 :(得分:1)

这是我的ThousandNumberEditText班级

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

<.ThousandNumberEditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    />

答案 8 :(得分:1)

您可以使用此方法:

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

要获取原始文本,请使用此:

String input = myEditText.getText().toString();
input = input.replace(",", "");

答案 9 :(得分:0)

由于我有同样的问题,我决定找到解决方案

在下面找到我的功能,希望它可以帮助人们找到解决方案

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

                        }

                    }
                }

            }
        });

答案 10 :(得分:0)

我只是想放comma,这对我有用:

String.format("%,.2f", myValue);

答案 11 :(得分:0)

此处的答案缺少一种处理实际用户输入的方法,例如删除字符或复制和粘贴。这是一个EditText字段。如果要添加格式,则需要支持编辑该格式的值。

根据您的用例,此实现仍然存在缺陷。我不在乎十进制值,并假设我只会处理整数。在此页面上,如何处理以及如何处理实际的国际化已经足够了,我将其留给读者练习。如果需要这样做,添加“。”应该不会太困难。正则表达式保留小数;您只需注意承认数字字符串仍然具有非数字字符即可。

旨在将其用于多个活动。对其进行一次新建,为其提供编辑文本和数据模型,然后将其忽略。如果不需要模型绑定,可以将其删除。

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

总的来说,它是:

  • 确定在字符串被编辑后实际上在哪个数字中
  • 如果未编辑数字,则将编辑处理为字符串的数字版本
  • 将数字转换回格式化的字符串
  • 根据开始编辑的位置以及添加了多少文本来确定光标的位置

它也可以很好地处理完全删除的输入,整数溢出和错误输入等极端情况。

答案 12 :(得分:0)

在这里,我已经测试了我的应用程序代码。文本观察程序如何以货币千(湖货币)添加逗号。

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

//在双精度变量上获取金额(在textwatcher上,editetxt值获取)。

String amount = Objects.requireNonNull(inputEdtHawalaRate.getText()).toString().trim();
double hawalaAmount = 0.0;

 String[] a = amount.split(",");
            finalAmount = TextUtils.join("", a);
            hawalaAmount = Double.parseDouble(finalAmount);

答案 13 :(得分:0)

您可以使用自定义 TextInputEditText :

public class NumberTextInputEditText extends TextInputEditText {

public NumberTextInputEditText(@NonNull Context context) {
    super(context);
}

public NumberTextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
}

public NumberTextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    addTextChangedListener(textWatcher);
}

public String formatNumber(double number) {
    DecimalFormat decimalFormat = new DecimalFormat("#,###");
    return decimalFormat.format(number);
}

public TextWatcher textWatcher = new TextWatcher() {
    @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) {
        removeTextChangedListener(this);
        String text = getText().toString();
        String format = "";
        if (!TextUtils.isEmpty(text)) {
            try {
                format = formatNumber(Double.parseDouble(new BigDecimal(text.replaceAll(",", "")).toString()));
            } catch (NumberFormatException e) {
                format = "";
            }
            setText(format);
            setSelection(format.length());
        }
        addTextChangedListener(this);
    }
};}

只需像布局中的视图一样使用它:

<com.your.package.name.NumberTextInputEditText
  android:layout_width="match_parent"
  android:layout_height="wrap_content"/>