69

我正在创建一个转换器应用程序。 我想设置EditText以便当用户输入要转换,的数字时,一旦数字增加 3 位,千位分隔符(
低于 4 位数字恢复正常。
有什么帮助吗?

4

15 回答 15

56

终于解决了问题

即使答案为时已晚。我已经研究了很多来完成任务以获得正确的结果但不能。所以我终于解决了我们正在搜索的问题,并为谷歌搜索者提供了这个答案,以节省他们的搜索时间。

以下代码的特征

  1. EditText在文本更改时放入千位分隔符。

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

  3. 在开始时忽略0输入。

只需复制以下名为的类

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

吉特

于 2015-12-14T11:04:41.290 回答
52

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

这不适用于浮点输入。并且注意不要使用 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
}
于 2012-09-09T11:53:28.097 回答
37
public static String doubleToStringNoDecimal(double d) {
    DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.US);
    formatter.applyPattern("#,###");
    return formatter.format(d);
}
于 2013-12-25T17:08:13.070 回答
9

这个示例应用程序清楚地解构了格式数字。

总结一下上面的链接,TextWatcherafterTextChanged()方法格式中使用 a 和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);
}
于 2016-08-06T08:39:31.140 回答
6

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

改进:

  1. 数千个分隔符和十进制标记是区域设置感知的,即它们根据Locale设备的使用。
  2. 在中间删除或添加元素后光标位置也不会改变(在他的答案中光标被重置到最后)。
  3. 代码的整体质量得到了特别的改进getDecimalFormattedString

代码:

    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,"");
        }
    }
于 2017-12-08T22:21:23.593 回答
4

与其他答案相比,此解决方案具有一些优势。例如,即使用户编辑数字的开头或中间,它也会保留用户的光标位置。其他解决方案总是将光标跳到数字的末尾。它处理小数和整数,以及使用除.小数分隔符和,千位分组分隔符以外的字符的语言环境。

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

然后在xml中:

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

最后注册观察者:

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

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

于 2017-09-01T03:41:43.753 回答
2

这是我的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"
    />
于 2017-09-14T03:43:22.930 回答
2

我只是想comma被安置,这对我有用:

String.format("%,.2f", myValue);
于 2018-10-26T03:46:49.907 回答
2

您可以使用此方法:

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(",", "");
于 2019-03-31T18:41:08.910 回答
1

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

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

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

                        }

                    }
                }

            }
        });
于 2013-08-16T12:08:34.073 回答
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()

你可以稍微改变一下并在textchangelistener上使用它。祝你好运

于 2016-01-19T12:41:13.177 回答
1

这里的答案缺乏处理实际用户输入的方法,例如删除字符或复制和粘贴。这是一个 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();
        }
    }
}

在高层次上,它的作用是:

  • 确定在编辑后哪些数字实际上在字符串中
  • 如果未编辑数字,则处理对字符串的数字版本的编辑
  • 将数字转换回格式化字符串
  • 根据编辑开始的位置和添加的文本量来确定光标的位置

它还可以很好地处理边缘情况,例如完全删除的输入、整数溢出和错误输入。

于 2019-05-28T13:11:23.753 回答
1

您可以使用自定义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"/>
于 2021-01-18T14:58:47.190 回答
0

在这里,我测试了我的应用程序代码。text-watcher 如何在千币、湖币中添加逗号。

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

// 获取 double 类型变量的数量(在 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);
于 2019-09-14T11:34:01.040 回答
0

由于我们的客户遍布全球,因此我一直在寻找一种区域设置感知解决方案。所以我建立在dr0pdb的答案之上。

这是我为解决此问题而创建的 TextWatcher 类(在 kotlin 中)。

https://github.com/abhilashd-locus/edittext-locale-aware-thousands-separator

特征:

  • 在用户键入时动态添加千位分隔符
  • 在字符串之间启用编辑,而不仅仅是在结尾处
  • 千位分隔样式基于区域设置(例如:100,000 与 1,00,000)
  • 千位分隔符和十进制标记的符号基于区域设置(例如:100,000.00 与 100.000,00)
  • 支持所有语言和地区

缺点:

  • 不支持复制/粘贴操作
  • 在从右到左的语言(例如阿拉伯语)中,光标会在删除第一个数字时跳到末尾

.

// ThousandsSeparatorTextWatcher.kt --> add this TextWatcher to the 
// EditText you want to add the functionality of dynamic locale aware thousands separator
class ThousandsSeparatorTextWatcher(private var editText: EditText?, private val callback: TextChangedCallback) : TextWatcher {

//keeping a count of the digits before the cursor to reset the cursor at the correct place
private var digitsBeforeCursor = -1
private val thousandSeparator: Char = DecimalFormatSymbols(Locale.getDefault()).groupingSeparator
private val decimalMarker: Char = DecimalFormatSymbols(Locale.getDefault()).decimalSeparator

init {
    editText?.apply {

        addTextChangedListener(this@ThousandsSeparatorTextWatcher)

        //disabling copy/paste to avoid format and parse errors
        disableTextSelection(this)

        //diabling text selection
        isLongClickable = false
        setTextIsSelectable(false)

        //ensuring correct input type
        keyListener = DigitsKeyListener.getInstance("0123456789$decimalMarker");
    }
}

private fun disableTextSelection(editText: EditText) {

    editText.customSelectionActionModeCallback = object : android.view.ActionMode.Callback {

        override fun onActionItemClicked(mode: android.view.ActionMode?, item: MenuItem?) = false

        override fun onCreateActionMode(mode: android.view.ActionMode?, menu: Menu?) = false

        override fun onPrepareActionMode(mode: android.view.ActionMode?, menu: Menu?) = false

        override fun onDestroyActionMode(mode: android.view.ActionMode?) {}
    }
}

/***
 * We are going to calculate the number of numeric digits before the cursor when user starts editing
 * We will keep a count of this number to reset the cursor to the correct position after editing is complete
 */
override fun beforeTextChanged(sequenceBeforeEdit: CharSequence, startPos: Int, count: Int, after: Int) {

    val textBeforeEdit = sequenceBeforeEdit.toString()

    if (textBeforeEdit.isEmpty()) {
        //in an empty string, cursor position is at 1 if a character is being added (after == 1)
        //if a character is not being added, cursor position remains at the beginning
        digitsBeforeCursor = if (after == 0) -1 else 1
        return
    }

    digitsBeforeCursor = if (after == 0) {
        //if characters are being removed
        //count will always be 1 since we have disabled selection (in which case count will be equal to the number of characters selected)
        val textBeforeNewCursor = textBeforeEdit.substring(0, startPos)
        textBeforeNewCursor.count { it != thousandSeparator }
    } else {
        //if characters are being added
        //after will always be 1 since we have disabled pasting (in which case after will be equal to the number of characters being pasted)
        if (startPos == textBeforeEdit.length) {
            //if adding a character to the end of the string
            textBeforeEdit.count { it != thousandSeparator } + 1
        } else {
            //if adding a character in between the string
            val textBeforeNewCursor = textBeforeEdit.substring(0, startPos + 1)
            textBeforeNewCursor.count { it != thousandSeparator }
        }
    }
}

override fun onTextChanged(textAfterEdit: CharSequence, start: Int, before: Int, count: Int) {}

/***
 * We will get the numeric value in the editText after stripping all the formatting
 * We will then reformat this number to add the correct thousands separation and decimal marker according to the locale
 * We then set the cursor to the correct position as we calculated in beforeTextChanged()
 */
override fun afterTextChanged(editable: Editable) {

    val text = editable.toString()

    //if the EditText is cleared, trigger callback with a null value to indicate an empty field
    if (text.isEmpty()) {
        digitsBeforeCursor = -1
        callback.onChanged(null)
        return
    }

    //get the double value of the entered number
    val numberValue = getNumberFromFormattedCurrencyText(text)

    //re-format the number to get the correct separation format and symbols
    var newText = getCurrencyFormattedAmountValue(numberValue)

    //If user was inputting decimal part of the number, reformatting will return a string without decimal point.
    //So we need to add it back after the reformatting is complete
    if (text.endsWith(decimalMarker)) {
        newText += decimalMarker
    } else if (text.endsWith(decimalMarker + "0")) {
        newText += decimalMarker + "0"
    }

    //removing the listener to prevent infinite triggers
    editText?.removeTextChangedListener(this)

    //set the reformatted text
    editText?.setText(newText)

    //send the number typed to the callback
    callback.onChanged(numberValue)

    //set the cursor to the right position after reformatting the string
    if (digitsBeforeCursor != -1) {
        var numbersParsed = 0
        for (i in newText.indices) {
            if (newText[i] != thousandSeparator) {
                numbersParsed++
            }
            if (numbersParsed == digitsBeforeCursor) {
                editText?.setSelection(i + 1)
                break
            }
        }
        digitsBeforeCursor = -1
    }

    //add the listener back
    editText?.addTextChangedListener(this)
}

/***
 * Function to remove the listener and release reference to the EditText
 */
fun removeWatcherFromEditText() {
    editText?.removeTextChangedListener(this)
    editText = null
}

interface TextChangedCallback {
    fun onChanged(newNumber: Double?)
}

companion object{
    
    @JvmStatic
    fun getNumberFromFormattedCurrencyText(formattedText: String?) = formattedText?.let {
        val numberFormat = NumberFormat.getNumberInstance(Locale.getDefault())
        try {
            numberFormat.parse(it)?.toDouble()
        } catch (exception: ParseException) {
            0.0
        }
    } ?: 0.0

    @JvmStatic
    fun getCurrencyFormattedAmountValue(amount: Double?) = amount?.let {
        val numberFormat = NumberFormat.getNumberInstance(Locale.getDefault())
        numberFormat.maximumFractionDigits = 2
        numberFormat.format(amount)
    } ?: ""
}
}
于 2021-10-03T09:37:18.017 回答