Android-как разрешить только определенное количество знаков после запятой

знаете ли вы какой-либо метод, чтобы убедиться, что пользователи могут вводить только цифры с максимальным количеством десятичных знаков. Я не знаю, как решить эту проблему. В базе данных MS SQL я собираюсь отправить данные из своего приложения, у меня есть столбцы с этим типом decimal(8,3) Теперь, учитывая тип данных столбца, который, наконец, будет хранить значение, которое я хочу проверить в Android, я рассмотрел эти два случая:

  1. если пользователь вводит число без десятичных знаков, максимальное число цифр должно быть 8
  2. если пользователь вводит число с десятичными знаками, максимальное количество цифр должно быть 8 (включая цифры справа от десятичной точки)

теперь я уверен в первом случае, но не так много о втором. правильно ли фиксировать количество максимальных цифр(например, всегда 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 (учитывая оба числа слева и справа от десятичного знака точка)

редактировать

Ну, теперь я пробую то, что предложил Жуан Суза, и вот что я пробовал:

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 ответов


Я бы пошел на фильтр в самом тексте редактирования с силой регулярного выражения. Первое регулярное выражение:

^\-?(\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.

правильно ли я понял проблему, которую вы описали?

-- EDIT

хорошо, я был почти там. Из того, что я понимаю, decimal(8,3) означает не более 8 цифр, включая цифры слева или справа от десятичной точки, начиная от -99999.999 to 99999.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, похоже, делают то же самое.


у меня answser для вас, я также страдала много в такой ситуации.: D: P

я реализовал это для максимум 4 цифр слева и 2 справа от десятичной точки ex: 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));

надеюсь, что вы можете преобразовать мой код в соответствии с вашими потребностями.


проблема, которую вы описываете-это именно то, что Замаскированный EditText предназначен для использования. :)