Ограничить количество десятичных знаков в Android EditText - PullRequest
111 голосов
/ 18 марта 2011

Я пытаюсь написать приложение, которое поможет вам управлять своими финансами.Я использую поле EditText, где пользователь может указать сумму денег.

Я установил inputType на numberDecimal, что прекрасно работает, за исключением того, что это позволяет людям вводить цифры, такие как 123.122 что не идеально подходит для денег.

Есть ли способ ограничить количество символов после десятичной точки двумя?

Ответы [ 33 ]

5 голосов
/ 18 сентября 2012

Немного улучшенное решение @Pinhassi.

Работает очень хорошо.Он проверяет объединенные строки.

public class DecimalDigitsInputFilter implements InputFilter {

Pattern mPattern;

public DecimalDigitsInputFilter() {
    mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)");

}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

    String formatedSource = source.subSequence(start, end).toString();

    String destPrefix = dest.subSequence(0, dstart).toString();

    String destSuffix = dest.subSequence(dend, dest.length()).toString();

    String result = destPrefix + formatedSource + destSuffix;

    result = result.replace(",", ".");

    Matcher matcher = mPattern.matcher(result);

    if (matcher.matches()) {
        return null;
    }

    return "";
}

 }
5 голосов
/ 18 марта 2011

Попробуйте использовать NumberFormat.getCurrencyInstance () для форматирования вашей строки, прежде чем поместить ее в TextView.

Что-то вроде:

NumberFormat currency = NumberFormat.getCurrencyInstance();
myTextView.setText(currency.format(dollars));

Редактировать - Нет входного типа для валюты, который я мог бы найти в документах. Я предполагаю, что это потому, что есть некоторые валюты, которые не следуют тому же правилу для десятичных знаков, например, японская иена.

Как упомянул LeffelMania, вы можете исправить ввод данных пользователем, используя вышеуказанный код с TextWatcher, установленным на вашем EditText.

5 голосов
/ 03 августа 2015

Я изменил вышеуказанные решения и создал следующий. Вы можете установить количество цифр до и после десятичной точки.

public class DecimalDigitsInputFilter implements InputFilter {

private final Pattern mPattern;

public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
    mPattern = Pattern.compile(String.format("[0-9]{0,%d}(\\.[0-9]{0,%d})?", digitsBeforeZero, digitsAfterZero));
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    Matcher matcher = mPattern.matcher(createResultString(source, start, end, dest, dstart, dend));
    if (!matcher.matches())
        return "";
    return null;
}

private String createResultString(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    String sourceString = source.toString();
    String destString = dest.toString();
    return destString.substring(0, dstart) + sourceString.substring(start, end) + destString.substring(dend);
}

}

3 голосов
/ 21 декабря 2015

Я изменил ответ №6 (от Favas Kv), потому что там можно поставить только точку на первой позиции.

final InputFilter [] filter = { new InputFilter() {

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
                               Spanned dest, int dstart, int dend) {
        StringBuilder builder = new StringBuilder(dest);
        builder.replace(dstart, dend, source
                .subSequence(start, end).toString());
        if (!builder.toString().matches(
                "(([1-9]{1})([0-9]{0,4})?(\\.)?)?([0-9]{0,2})?"

        )) {
            if(source.length()==0)
                return dest.subSequence(dstart, dend);
            return "";
        }
        return null;
    }
}};
3 голосов
/ 26 мая 2013

Все ответы здесь довольно сложные, я попытался сделать их намного проще. Посмотрите на мой код и решите сами -

int temp  = 0;
int check = 0;

editText.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

        if(editText.getText().toString().length()<temp)
        {
            if(!editText.getText().toString().contains("."))
                editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()-1) });
            else
                editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) });

        }

        if(!editText.getText().toString().contains("."))
        {
            editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+1) });
            check=0;
        }


        else if(check==0)
        {
            check=1;
            editText.setFilters(new InputFilter[] { new InputFilter.LengthFilter(editText.getText().toString().length()+2) });
        }
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        temp = editText.getText().toString().length();


    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub

    }
});
3 голосов
/ 26 августа 2012
DecimalFormat form = new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.US));
    EditText et; 
    et.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

        if (actionId == EditorInfo.IME_ACTION_DONE) {
            double a = Double.parseDouble(et.getText().toString());
            et.setText(form.format(a));
        }
        return false;
    }
});

При выходе из фазы редактирования форматируется поле в нужном формате.На данный момент он имеет только 2 десятичных знака.Я думаю, что это довольно простой способ сделать это.

3 голосов
/ 29 июля 2014

Я улучшил решение, использующее регулярное выражение Пинхасси, поэтому оно также правильно обрабатывает крайние случаи.Перед проверкой правильности ввода сначала создается последняя строка, как описано в документации для Android.

public class DecimalDigitsInputFilter implements InputFilter {

    private Pattern mPattern;

    private static final Pattern mFormatPattern = Pattern.compile("\\d+\\.\\d+");

    public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal) {
        mPattern = Pattern.compile(
            "^\\d{0," + digitsBeforeDecimal + "}([\\.,](\\d{0," + digitsAfterDecimal +
                "})?)?$");
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, 
                               int dstart, int dend) {

        String newString =
            dest.toString().substring(0, dstart) + source.toString().substring(start, end) 
            + dest.toString().substring(dend, dest.toString().length());

        Matcher matcher = mPattern.matcher(newString);
        if (!matcher.matches()) {
            return "";
        }
        return null;
    }
}

Использование:

editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});
3 голосов
/ 03 сентября 2015

Класс Simple Helper предназначен для предотвращения ввода пользователем более 2 цифр после десятичной дроби:

public class CostFormatter  implements TextWatcher {

private final EditText costEditText;

public CostFormatter(EditText costEditText) {
    this.costEditText = costEditText;
}

@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 synchronized void afterTextChanged(final Editable text) {
    String cost = text.toString().trim();

    if(!cost.endsWith(".") && cost.contains(".")){
        String numberBeforeDecimal = cost.split("\\.")[0];
        String numberAfterDecimal = cost.split("\\.")[1];

        if(numberAfterDecimal.length() > 2){
            numberAfterDecimal = numberAfterDecimal.substring(0, 2);
        }
        cost = numberBeforeDecimal + "." + numberAfterDecimal;
    }
    costEditText.removeTextChangedListener(this);
    costEditText.setText(cost);
    costEditText.setSelection(costEditText.getText().toString().trim().length());
    costEditText.addTextChangedListener(this);
}
}
2 голосов
/ 23 мая 2014

Мне очень понравился ответ Пинхасси, но я заметил, что после того, как пользователь ввел указанные цифры после десятичной точки, вы больше не можете вводить текст слева от десятичной точки.Проблема заключалась в том, что решение проверяло только предыдущий введенный текст, а не текущий вводимый текст.Итак, вот мое решение, которое вставляет новый символ в исходный текст для проверки.

package com.test.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.text.InputFilter;
import android.text.Spanned;
import android.util.Log;

public class InputFilterCurrency implements InputFilter {
    Pattern moPattern;

    public InputFilterCurrency(int aiMinorUnits) {
        // http://www.regexplanet.com/advanced/java/index.html
        moPattern=Pattern.compile("[0-9]*+((\\.[0-9]{0,"+ aiMinorUnits + "})?)||(\\.)?");

    } // InputFilterCurrency

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        String lsStart  = "";
        String lsInsert = "";
        String lsEnd    = "";
        String lsText   = "";

        Log.d("debug", moPattern.toString());
        Log.d("debug", "source: " + source + ", start: " + start + ", end:" + end + ", dest: " + dest + ", dstart: " + dstart + ", dend: " + dend );

        lsText = dest.toString();

        // If the length is greater then 0, then insert the new character
        // into the original text for validation
        if (lsText.length() > 0) {

            lsStart = lsText.substring(0, dstart);
            Log.d("debug", "lsStart : " + lsStart);
            // Check to see if they have deleted a character
            if (source != "") {
                lsInsert = source.toString();
                Log.d("debug", "lsInsert: " + lsInsert);
            } // if
            lsEnd = lsText.substring(dend);
            Log.d("debug", "lsEnd   : " + lsEnd);
            lsText = lsStart + lsInsert + lsEnd;
            Log.d("debug", "lsText  : " + lsText);

        } // if

        Matcher loMatcher = moPattern.matcher(lsText);
        Log.d("debug", "loMatcher.matches(): " + loMatcher.matches() + ", lsText: " + lsText);
        if(!loMatcher.matches()) {
            return "";
        }
        return null;

    } // CharSequence

} // InputFilterCurrency

И вызов для установки фильтра editText

editText.setFilters(new InputFilter[] {new InputFilterCurrency(2)});

Ouput with two decimal places
05-22 15:25:33.434: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)?
05-22 15:25:33.434: D/debug(30524): source: 5, start: 0, end:1, dest: 123.4, dstart: 5, dend: 5
05-22 15:25:33.434: D/debug(30524): lsStart : 123.4
05-22 15:25:33.434: D/debug(30524): lsInsert: 5
05-22 15:25:33.434: D/debug(30524): lsEnd   : 
05-22 15:25:33.434: D/debug(30524): lsText  : 123.45
05-22 15:25:33.434: D/debug(30524): loMatcher.matches(): true, lsText: 123.45

Ouput inserting a 5 in the middle
05-22 15:26:17.624: D/debug(30524): [0-9]*+((\.[0-9]{0,2})?)||(\.)?
05-22 15:26:17.624: D/debug(30524): source: 5, start: 0, end:1, dest: 123.45, dstart: 2, dend: 2
05-22 15:26:17.624: D/debug(30524): lsStart : 12
05-22 15:26:17.624: D/debug(30524): lsInsert: 5
05-22 15:26:17.624: D/debug(30524): lsEnd   : 3.45
05-22 15:26:17.624: D/debug(30524): lsText  : 1253.45
05-22 15:26:17.624: D/debug(30524): loMatcher.matches(): true, lsText: 1253.45
2 голосов
/ 18 августа 2016

Как уже говорили другие, я добавил этот класс в свой проект и установил фильтр на EditText, который я хочу.

Фильтр скопирован из ответа @ Pixel. Я просто собираю все это вместе.

public class DecimalDigitsInputFilter implements InputFilter {

    Pattern mPattern;

    public DecimalDigitsInputFilter() {
        mPattern = Pattern.compile("([1-9]{1}[0-9]{0,2}([0-9]{3})*(\\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\\.[0-9]{0,2})?|0(\\.[0-9]{0,2})?|(\\.[0-9]{1,2})?)");

    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

        String formatedSource = source.subSequence(start, end).toString();

        String destPrefix = dest.subSequence(0, dstart).toString();

        String destSuffix = dest.subSequence(dend, dest.length()).toString();

        String result = destPrefix + formatedSource + destSuffix;

        result = result.replace(",", ".");

        Matcher matcher = mPattern.matcher(result);

        if (matcher.matches()) {
            return null;
        }

        return "";
    }
}

Теперь установите фильтр в вашем EditText следующим образом.

mEditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter()});

Здесь одна важная вещь - это решает мою проблему, состоящую в том, чтобы не разрешать показывать более двух цифр после десятичной точки в этом EditText, но проблема в том, что когда я getText() из этого EditText, он возвращает весь ввод Я напечатал.

Например, после применения фильтра к EditText я попытался установить вход 1.5699856987. Так что на экране он показывает 1,56, что идеально.

Затем я хотел использовать этот ввод для некоторых других вычислений, поэтому я хотел получить текст из этого поля ввода (EditText). Когда я позвонил mEditText.getText().toString(), он возвращает 1.5699856987, что было неприемлемо в моем случае.

Поэтому мне пришлось снова проанализировать значение после получения его из EditText.

BigDecimal amount = new BigDecimal(Double.parseDouble(mEditText.getText().toString().trim()))
    .setScale(2, RoundingMode.HALF_UP);

setScale добивается цели после получения полного текста из EditText.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...