安卓自定义EditText(货币格式)

3

我有一个自定义EditText,它可以将输入转换并且也能够反转。然而,它总是会将输入变成十进制,并且只保留1或2位小数。现在我正在开发一款需要整数的计算应用程序。如何将这个自定义EditText设置为只接受整数输入并输出?

代码:

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class NumericEditText extends EditText {
    private final char GROUPING_SEPARATOR = DecimalFormatSymbols.getInstance().getGroupingSeparator();
    private final char DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator();
    private final String LEADING_ZERO_FILTER_REGEX = "^0+(?!$)";

    private String mDefaultText = null;
    private String mPreviousText = "";
    private String mNumberFilterRegex = "[^\\d\\" + DECIMAL_SEPARATOR + "]";

    /**
     * Interface to notify listeners when numeric value has been changed or cleared
     */
    public interface NumericValueWatcher {
        /**
         * Fired when numeric value has been changed
         * @param newValue new numeric value
         */
        void onChanged(double newValue);

        /**
         * Fired when numeric value has been cleared (text field is empty)
         */
        void onCleared();
    }

    private List<NumericValueWatcher> mNumericListeners = new ArrayList<NumericValueWatcher>();
    private final TextWatcher mTextWatcher = new TextWatcher() {
        private boolean validateLock = false;

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

            // valid decimal number should not have more than 2 decimal separators
            if (StringUtils.countMatches(s.toString(), String.valueOf(DECIMAL_SEPARATOR)) > 1) {
                validateLock = true;
                setText(mPreviousText); // cancel change and revert to previous input
                setSelection(mPreviousText.length());
                validateLock = false;
                return;
            }

            if (s.length() == 0) {
                handleNumericValueCleared();
                return;
            }

            setTextInternal(format(s.toString()));
            setSelection(getText().length());
            handleNumericValueChanged();
        }

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

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // do nothing
        }
    };

    private void handleNumericValueCleared() {
        mPreviousText = "";
        for (NumericValueWatcher listener : mNumericListeners) {
            listener.onCleared();
        }
    }

    private void handleNumericValueChanged() {
        mPreviousText = getText().toString();
        for (NumericValueWatcher listener : mNumericListeners) {
            listener.onChanged(getNumericValue());
        }
    }

    public NumericEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        addTextChangedListener(mTextWatcher);
        setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // disable moving cursor
                setSelection(getText().length());
            }
        });
    }

    /**
     * Add listener for numeric value changed events
     * @param watcher   listener to add
     */
    public void addNumericValueChangedListener(NumericValueWatcher watcher) {
        mNumericListeners.add(watcher);
    }

    /**
     * Remove all listeners to numeric value changed events
     */
    public void removeAllNumericValueChangedListeners() {
        while (!mNumericListeners.isEmpty()) {
            mNumericListeners.remove(0);
        }
    }

    /**
     * Set default numeric value and how it should be displayed, this value will be used if
     * {@link #clear} is called
     * @param defaultNumericValue   numeric value
     * @param defaultNumericFormat  display format for numeric value
     */
    public void setDefaultNumericValue(double defaultNumericValue, final String defaultNumericFormat) {
        mDefaultText = String.format(defaultNumericFormat, defaultNumericValue);
        setTextInternal(mDefaultText);
    }

    /**
     * Clear text field and replace it with default value set in {@link #setDefaultNumericValue} if
     * any
     */
    public void clear() {
        setTextInternal(mDefaultText != null ? mDefaultText : "");
        if (mDefaultText != null) {
            handleNumericValueChanged();
        }
    }

    /**
     * Return numeric value repesented by the text field
     * @return  numeric value or {@link Double.NaN} if not a number
     */
    public double getNumericValue() {
        String original = getText().toString().replaceAll(mNumberFilterRegex, "");
        try {
            return NumberFormat.getInstance().parse(original).doubleValue();
        } catch (ParseException e) {
            return Double.NaN;
        }
    }

    /**
     * Add grouping separators to string
     * @param original  original string, may already contains incorrect grouping separators
     * @return  string with correct grouping separators
     */
    private String format(final String original) {
        final String[] parts = original.split("\\" + DECIMAL_SEPARATOR, -1);
        String number = parts[0] // since we split with limit -1 there will always be at least 1 part
                .replaceAll(mNumberFilterRegex, "")
                .replaceFirst(LEADING_ZERO_FILTER_REGEX, "");

        // add grouping separators, need to reverse back and forth since Java regex does not support
        // right to left matching
        number = StringUtils.reverse(
                StringUtils.reverse(number).replaceAll("(.{3})", "$1" + GROUPING_SEPARATOR));
        // remove leading grouping separator if any
        number = StringUtils.removeStart(number, String.valueOf(GROUPING_SEPARATOR));

        // add fraction part if any
        if (parts.length > 1) {
            number += DECIMAL_SEPARATOR + parts[1];
        }

        return number;
    }

    /**
     * Change display text without triggering numeric value changed
     * @param text  new text to apply
     */
    private void setTextInternal(String text) {
        removeTextChangedListener(mTextWatcher);
        setText(text);
        addTextChangedListener(mTextWatcher);
    }
}

示例:

输入10000 一瞬间变成10,000, 输入10000.12 它将是10,000.12

我的尝试:

                int input2 = 0;
                String text2 = etpersen2.getText().toString();
                if (text2.length() > 0)
                     input2 = Integer.parseInt(text2);
                String e = String.valueOf(input2);

                etresult.setText("" + e);
1个回答

1
使用Math.round()应该将浮点数四舍五入到最近的整数。它返回一个int值,因此使用(int)进行类型转换是多余的。
public class Test{ 

   public static void main(String args[]){
      double d = 100.675;
      double e = 100.500;
      float f = 100;
      float g = 90f;

      System.out.println(Math.round(d));
      System.out.println(Math.round(e)); 
      System.out.println(Math.round(f)); 
      System.out.println(Math.round(g)); 
   }
}

听起来很有前途,我会尝试。 - Jedi Fighter
如何使用它?--->> int x = (int) Math.round(TheInput); <----- 这样用错了吗? - Jedi Fighter
非常抱歉反复询问,但我很好奇,Math.round()也会处理NaN吗?我的意思是,如果输入是NaN会怎样? - Jedi Fighter
1
是的,问题已经解决了。我在onfocuschangelistener中使用了这个技巧。如果(output == (long) output),那么e = String.format("%d", (long) output);否则,e = String.format("%.2f", output);editText.setText(e); - Jedi Fighter
1
太好了!!!我还找到了一些好的参考链接。可能对其他人有帮助...
  1. http://codereview.stackexchange.com/questions/38317/optimize-parsing-of-number-for-currency-conversion
2)https://dev59.com/rW865IYBdhLWcg3wa9803)https://dev59.com/23E95IYBdhLWcg3wSb3P
- Devraj
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接