Android - 如何只允许一定数量的小数位

时间:2014-11-22 12:42:53

标签: java android android-edittext

您知道有哪些方法可以确保用户只能输入最大小数位数的数字。 我不知道如何解决这个问题。在MS SQL数据库中,我将从我的应用程序发送数据我有这种类型的列decimal(8,3) 现在考虑最终要存储我想在Android中验证的值的列的数据类型,我考虑过这两种情况:

  1. 如果用户输入没有小数的数字,则最大位数必须为8
  2. 如果用户输入带小数的数字,则最大位数必须为8(包括小数点右边的数字)
  3. 现在我确定第一种情况,但不是第二种情况。 保持最大位数固定是否正确(例如,始终为8)?或者我应该考虑允许小数点左边最多8位数,小数点右边3点?

    无论哪种方式,这都是我在Android中尝试过的方法:

    mQuantityEditText.addTextChangedListener(new TextWatcher() {
                @Override
                public void afterTextChanged(Editable s) {
                    String str = mQuantityEditText.getText().toString();
                    DecimalFormat format = (DecimalFormat) DecimalFormat
                            .getInstance();
                    DecimalFormatSymbols symbols = format.getDecimalFormatSymbols();
                    char sep = symbols.getDecimalSeparator();
    
                    int indexOFdec = str.indexOf(sep);
    
                    if (indexOFdec >= 0) {
                        if (str.substring(indexOFdec, str.length() - 1).length() > 3) {                     
                            s.replace(0, s.length(),
                                    str.substring(0, str.length() - 1));                        
                        }
                    }
                }
    
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count,
                        int after) {
    
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before,
                        int count) {
    
                }
            });
    

    尽管如此,上面的代码处理了最大小数位数。它不限制EditText中允许的总位数。

    您认为可以帮助我改进代码,以便它处理最大小数位数和EditText中允许的总位数(考虑小数点左侧和右侧的数字)

    修改

    好吧,现在我正在尝试JoãoSousa建议的内容,这就是我尝试过的内容:

    1)我定义了一个实现InputFilter

    的类
    public class NumberInputFilter implements InputFilter {
        private Pattern mPattern;   
    
        public NumberInputFilter(int precision, int scale) {        
            String pattern="^\\-?(\\d{0," + (precision-scale) + "}|\\d{0," + (precision-scale) + "}\\.\\d{0," + scale + "})$";
            this.mPattern=Pattern.compile(pattern);
    
        }
    
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
             if (end > start) {
                 // adding: filter   
                 // build the resulting text
                 String destinationString = destination.toString();
                 String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
                 // return null to accept the input or empty to reject it
                 return resultingTxt.matches(this.mPattern.toString()) ? null : "";
             }
             // removing: always accept
             return null;
        }
    
    }
    

    2)试图使用这样的类:

    mQuantityEditText.setFilters(new InputFilter[] { new NumberInputFilter(8,3)} );
    

3 个答案:

答案 0 :(得分:9)

我会使用正则表达式的力量在编辑文本中寻找过滤器。首先是正则表达式:

^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$

也许有多种方法可以改善这种表达方式,但这确实很有用。

现在只需在edittext中设置输入过滤器,如下所示:

final String regex = "^\-?(\d{0,5}|\d{0,5}\.\d{0,3})$";
((EditText)rootView.findViewById(R.id.editText1)).setFilters(new InputFilter[] {
    new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end, Spanned destination, int destinationStart, int destinationEnd) {
            if (end > start) {
                // adding: filter   
                // build the resulting text
                String destinationString = destination.toString();
                String resultingTxt = destinationString.substring(0, destinationStart) + source.subSequence(start, end) + destinationString.substring(destinationEnd);
                // return null to accept the input or empty to reject it
                return resultingTxt.matches(regex) ? null : "";
            }
            // removing: always accept
            return null;
        }
    }
});

顺便说一句,我刚测试了这段代码,它的作用是:

  1. 用户最多可以输入8位数字;
  2. 用户输入'。'后,允许的最大小数为8。
  3. 我是否正确理解了您描述的问题?

    - 编辑

    好的,我差不多了。根据我的理解,十进制(8,3)表示最多8位数字,包括小数点左侧或右侧的数字,范围从-99999.99999999.999。 至少这是我从这句话Standard SQL requires that DECIMAL(5,2) be able to store any value with five digits and two decimals, so values that can be stored in the salary column range from -999.99 to 999.99中理解的内容。即使它来自MySQL文档,MSSQL文档似乎也是如此。

答案 1 :(得分:1)

我为你回答,在这种情况下我也遭受了很多痛苦。:D:P

我已经实现了这一点,左边最多4位,小数点右边2点:4444.99

这么小的变化需要实现我所做的: 需要做以下更改

1)复制CustomTextWatcher.java以跟踪editText的输入。

import java.text.NumberFormat;

import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.widget.EditText;

public class CustomTextWatcher implements TextWatcher {


    private NumberFormat nf = NumberFormat.getNumberInstance();
    private EditText et;
    private String tmp = "";
    private int moveCaretTo;
    private static final int INTEGER_CONSTRAINT = 4;
    private static final int FRACTION_CONSTRAINT = 2;
    private static final int MAX_LENGTH = INTEGER_CONSTRAINT
            + FRACTION_CONSTRAINT + 1;

    public CustomTextWatcher(EditText et) {
        this.et = et;
        nf.setMaximumIntegerDigits(INTEGER_CONSTRAINT);
        nf.setMaximumFractionDigits(FRACTION_CONSTRAINT);
        nf.setGroupingUsed(false);
    }

    public int countOccurrences(String str, char c) {
        int count = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == c) {
                count++;
            }
        }
        return count;
    }

    @Override
    public void afterTextChanged(Editable s) {
        et.removeTextChangedListener(this); // remove to prevent stackoverflow
        String ss = s.toString();
        int len = ss.length();
        int dots = countOccurrences(ss, '.');
        boolean shouldParse = dots <= 1
                && (dots == 0 ? len != (INTEGER_CONSTRAINT + 1)
                        : len < (MAX_LENGTH + 1));
        if (shouldParse) {
            if (len > 1 && ss.lastIndexOf(".") != len - 1) {
                try {

                    if (ss.contains(".")) {

                        String[] integerFractionStrings = ss.split("\\.");

                        Log.v("Check SS ", ss);

                        Log.v("second string", "Found"
                                + integerFractionStrings.length);

                        if (integerFractionStrings.length > 1) {

                            Log.v("integerFractionStrings",
                                    integerFractionStrings[1]);

                            if (integerFractionStrings[1].length() == 1
                                    && integerFractionStrings[1].charAt(0) == '0') {

                                et.setText(ss);

                                Log.v("second string", "size 1");
                            } else {

                                Log.v("second string", "> 1");

                                Double d = Double.parseDouble(ss);
                                if (d != null) {
                                    et.setText(nf.format(d));
                                }

                            }
                        }
                    } else {

                        Log.v("First string", "No dot");

                        Double d = Double.parseDouble(ss);
                        if (d != null) {
                            et.setText(nf.format(d));
                        }
                    }

                } catch (NumberFormatException e) {
                }
            }
        } else {

            Log.v("second string", "size 1");
            et.setText(tmp);
        }
        et.addTextChangedListener(this); // reset listener

        // tried to fix caret positioning after key type:
        if (et.getText().toString().length() > 0) {
            if (dots == 0 && len >= INTEGER_CONSTRAINT
                    && moveCaretTo > INTEGER_CONSTRAINT) {
                moveCaretTo = INTEGER_CONSTRAINT;
            } else if (dots > 0 && len >= (MAX_LENGTH)
                    && moveCaretTo > (MAX_LENGTH)) {
                moveCaretTo = MAX_LENGTH;
            }
            try {
                et.setSelection(et.getText().toString().length());
                // et.setSelection(moveCaretTo); <- almost had it :))
            } catch (Exception e) {
            }
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        moveCaretTo = et.getSelectionEnd();
        tmp = s.toString();
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        int length = et.getText().toString().length();
        if (length > 0) {
            moveCaretTo = start + count - before;
        }
    }
}

2)设置此类以通过以下方式检查您的editText。

EditText review_food_Price;

review_food_Price = (EditText) findViewById(R.id.food_Price);

review_food_Price.setRawInputType(InputType.TYPE_CLASS_NUMBER
                | InputType.TYPE_NUMBER_FLAG_DECIMAL);

review_food_Price.addTextChangedListener(new CustomTextWatcher(
                review_food_Price));

希望您可以根据需要转换我的代码。

答案 2 :(得分:0)

您描述的问题恰恰是Masked EditText的用途。 :)