Обмежте десяткові місця в Android EditText


125

Я намагаюся написати додаток, яке допоможе вам керувати своїми фінансами. Я використовую EditTextполе, де користувач може вказати суму грошей.

Я встановив inputTypeв numberDecimalякій працює відмінно, за винятком того, що це дозволяє людям вводити цифри , такі як 123.122, не ідеально підходить для грошей.

Чи є спосіб обмежити кількість символів після десяткової крапки до двох?


Ви можете написати регулярний вираз і перевірити зміст тексту для редагування, коли він втрачає фокус.
сліпота

Я знайшов InputFilterінтерфейс, він, здається, робить те, що мені хочеться developer.android.com/reference/android/text/method/… , але метод, filterякий я маю реалізувати, досить бентежить мене. Хтось уже написав такий Фільтр і знає, як ним користуватися?
Костянтин Вайц

Чи працює якесь із запропонованих рішень для локальних файлів RTL? Наскільки я можу сказати, вони не будуть ...
Нік

Відповіді:


118

Більш елегантним способом було б використання регулярного виразу (регулярного вираження) таким чином:

public class DecimalDigitsInputFilter implements InputFilter {

Pattern mPattern;

public DecimalDigitsInputFilter(int digitsBeforeZero,int digitsAfterZero) {
    mPattern=Pattern.compile("[0-9]{0," + (digitsBeforeZero-1) + "}+((\\.[0-9]{0," + (digitsAfterZero-1) + "})?)||(\\.)?");
}

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

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

}

Для його використання виконайте:

editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});

32
Привіт, є деякі крайові випадки, які все ще не вдається добре. Наприклад, після того, як я набираю 2,45, я схильний "переміщувати курсор на передню частину тексту". Я хочу створити текст 12.45, це не дозволить.
Cheok Yan Cheng

3
це не дозволяє змінювати цифри перед десятковим після введення користувачем двох цифр після коми.
Гаурав Сінгла

9
Прекрасне рішення, але воно не зовсім правильне. Матч не повинен перевіряти dest, він повинен перевіряти значення в edittext (dest.subSequence (0, dstart) + source.subSequence (start, end) + dest.subSequence (dend, dest.length ()))
Mihaela Romanca

7
Михаела має рацію, нам слід відповідати рядку, який намагається заповнити редакційний текст. Я знайшов, як об'єднатися в інше питання, наприклад, цей матч CharSequence = TextUtils.concat (dest.subSequence (0, dstart), source.subSequence (початок, кінець), dest.subSequence (dend, dest.length ())); Регекс викликав проблеми після цього, хоча я змінив його на це "^ \\ d {1," + цифриBeforeZero + "} (\\. \\ d {0," + цифриAfterZero + "})? $" Але ти " Після цього доведеться також перевірити, оскільки "1." діє з цим регулярним виразом, але він нам потрібен саме таким чином, щоб період можна було набрати.
dt0

6
Як би ви зробили цю роботу для коми (,)? Деякі регіони світу вводять десяткові числа з комами (наприклад: 123,45).
Андрій

65

Простіше рішення без використання регулярного вираження:

import android.text.InputFilter;
import android.text.Spanned;

/**
 * Input filter that limits the number of decimal digits that are allowed to be
 * entered.
 */
public class DecimalDigitsInputFilter implements InputFilter {

  private final int decimalDigits;

  /**
   * Constructor.
   * 
   * @param decimalDigits maximum decimal digits
   */
  public DecimalDigitsInputFilter(int decimalDigits) {
    this.decimalDigits = decimalDigits;
  }

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


    int dotPos = -1;
    int len = dest.length();
    for (int i = 0; i < len; i++) {
      char c = dest.charAt(i);
      if (c == '.' || c == ',') {
        dotPos = i;
        break;
      }
    }
    if (dotPos >= 0) {

      // protects against many dots
      if (source.equals(".") || source.equals(","))
      {
          return "";
      }
      // if the text is entered before the dot
      if (dend <= dotPos) {
        return null;
      }
      if (len - dotPos > decimalDigits) {
        return "";
      }
    }

    return null;
  }

}

Використовувати:

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

Що заважає мені вставляти нечислові символи в рядок типу "a"?
Костянтин Вайц

4
Це: <EditText ... android: inputType = "число" />
peceps

1
Це повинно бути: editText.setFilters (новий InputFilter [] {new DecimalDigitsInputFilter (2)});
фрак

6
Це не стосується випадку, коли я
набираю

1
Спасибі цьому корисно. Ми також можемо обмежити цифри перед десятковою точкою, використовуючи такий фільтр довжини. Kotlin: edtAnyAmount.filters = arrayOf <InputFilter> (InputFilter.LengthFilter (7), DecimalDigitsInputFilter (2))
Faldu Jaldeep

37

Така реалізація InputFilterвирішує проблему.

import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.DigitsKeyListener;

public class MoneyValueFilter extends DigitsKeyListener {
    public MoneyValueFilter() {
        super(false, true);
    }

    private int digits = 2;

    public void setDigits(int d) {
        digits = d;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
            Spanned dest, int dstart, int dend) {
        CharSequence out = super.filter(source, start, end, dest, dstart, dend);

        // if changed, replace the source
        if (out != null) {
            source = out;
            start = 0;
            end = out.length();
        }

        int len = end - start;

        // if deleting, source is empty
        // and deleting can't break anything
        if (len == 0) {
            return source;
        }

        int dlen = dest.length();

        // Find the position of the decimal .
        for (int i = 0; i < dstart; i++) {
            if (dest.charAt(i) == '.') {
                // being here means, that a number has
                // been inserted after the dot
                // check if the amount of digits is right
                return (dlen-(i+1) + len > digits) ? 
                    "" :
                    new SpannableStringBuilder(source, start, end);
            }
        }

        for (int i = start; i < end; ++i) {
            if (source.charAt(i) == '.') {
                // being here means, dot has been inserted
                // check if the amount of digits is right
                if ((dlen-dend) + (end-(i + 1)) > digits)
                    return "";
                else
                    break;  // return new SpannableStringBuilder(source, start, end);
            }
        }

        // if the dot is after the inserted part,
        // nothing can break
        return new SpannableStringBuilder(source, start, end);
    }
}

Чи можу я знати, чи є якась причина, що нам потрібно повернути SpannableStringBuilder замість null? Я тестую його з нулем, він також добре працює. Крім того, чи є нам необхідність успадкувати від DigitsKeyListener? Як використовується android: inputType = "numberDecimal" виконає всі "0123456789." виконання символів.
Cheok Yan Cheng

1
Добре працює. Велике спасибі.
Андрій Аулашка

34

Ось зразок InputFilter, який дозволяє лише максимум 4 цифри перед десятковою комою та максимум 1 цифру після цього.

Значення, що редагує текст, дозволяє: 555.2 , 555 , .2

Значення, що редагують текстові блоки: 55555.2 , 055.2 , 555.42

        InputFilter filter = new InputFilter() {
        final int maxDigitsBeforeDecimalPoint=4;
        final int maxDigitsAfterDecimalPoint=1;

        @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,"+(maxDigitsBeforeDecimalPoint-1)+"})?)?(\\.[0-9]{0,"+maxDigitsAfterDecimalPoint+"})?"

                        )) {
                    if(source.length()==0)
                        return dest.subSequence(dstart, dend);
                    return "";
                }

            return null;

        }
    };

    mEdittext.setFilters(new InputFilter[] { filter });

не пускає. щоб набрати
AmiNadimi

22

Я зробив кілька виправлень для рішення @Pinhassi. Він обробляє деякі випадки:

1.Ви можете перемістити курсор куди завгодно

2.minus обробка знаків

3. цифри перед = 2 і цифра після 4 = ви вводите 12.4545. Тоді, якщо ви хочете видалити ".", Це не дозволить.

public class DecimalDigitsInputFilter implements InputFilter {
    private int mDigitsBeforeZero;
    private int mDigitsAfterZero;
    private Pattern mPattern;

    private static final int DIGITS_BEFORE_ZERO_DEFAULT = 100;
    private static final int DIGITS_AFTER_ZERO_DEFAULT = 100;

    public DecimalDigitsInputFilter(Integer digitsBeforeZero, Integer digitsAfterZero) {
    this.mDigitsBeforeZero = (digitsBeforeZero != null ? digitsBeforeZero : DIGITS_BEFORE_ZERO_DEFAULT);
    this.mDigitsAfterZero = (digitsAfterZero != null ? digitsAfterZero : DIGITS_AFTER_ZERO_DEFAULT);
    mPattern = Pattern.compile("-?[0-9]{0," + (mDigitsBeforeZero) + "}+((\\.[0-9]{0," + (mDigitsAfterZero)
        + "})?)||(\\.)?");
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
    String replacement = source.subSequence(start, end).toString();
    String newVal = dest.subSequence(0, dstart).toString() + replacement
        + dest.subSequence(dend, dest.length()).toString();
    Matcher matcher = mPattern.matcher(newVal);
    if (matcher.matches())
        return null;

    if (TextUtils.isEmpty(source))
        return dest.subSequence(dstart, dend);
    else
        return "";
    }
}

Я думаю, що це повинно бути ідеальним рішенням, зробленим моїм днем. Дякую.
Пратік Бутані

1
@Omkar це неправильно. ця умова буде завжди вірною, навіть якщо довжина> 0, dest.length () == 0 завжди відповідає дійсності, навіть якщо ви редагуєте текст усього тексту більше ніж 0 ...
user924

@Omkar видаліть ваш коментар pls
user924

@android_dev, чому я не можу вводити негативні значення (мінус)?
user924

Якщо ви встановите android:inputType="number"або android:inputType="numberDecimal"це не дозволить набрати мінус, це android:digits="0123456789.-"не допоможе
user924

18

Інше рішення мені не подобається, і я створив своє. За допомогою цього рішення ви не можете вводити більше MAX_BEFORE_POINT цифри перед точкою, а десяткові знаки - не більше MAX_DECIMAL.

Ви просто не можете набрати цифру в надлишку, ніяких інших ефектів! Додатково, якщо ви пишете "." він набирає "0."

  1. Встановіть EditText у макеті так:

    android: inputType = "числоDecimal"

  2. Додайте слухача у своє створення. Якщо ви хочете змінити кількість цифр до і після точки, відредагуйте виклик на PerfectDecimal (str, NUMBER_BEFORE_POINT, NUMBER_DECIMALS), тут встановлено 3 і 2

    EditText targetEditText = (EditText)findViewById(R.id.targetEditTextLayoutId);
    
    targetEditText.addTextChangedListener(new TextWatcher() {
      public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
    
      public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
    
      public void afterTextChanged(Editable arg0) {
        String str = targetEditText.getText().toString();
        if (str.isEmpty()) return;
        String str2 = PerfectDecimal(str, 3, 2);
    
        if (!str2.equals(str)) {
            targetEditText.setText(str2);
            int pos = targetEditText.getText().length();
            targetEditText.setSelection(pos);
        }
      }
    });
  3. Включіть цю функцію:

    public String PerfectDecimal(String str, int MAX_BEFORE_POINT, int MAX_DECIMAL){
      if(str.charAt(0) == '.') str = "0"+str;
      int max = str.length();
    
      String rFinal = "";
      boolean after = false;
      int i = 0, up = 0, decimal = 0; char t;
      while(i < max){
        t = str.charAt(i);
        if(t != '.' && after == false){
            up++;
            if(up > MAX_BEFORE_POINT) return rFinal;
        }else if(t == '.'){
            after = true;
        }else{
            decimal++;
            if(decimal > MAX_DECIMAL)
                return rFinal;
        }
        rFinal = rFinal + t;
        i++;
      }return rFinal;
    }

І це зроблено!


1
Ура. Працюйте дуже добре, коли інший не працював для мене
ведмідь

1
Це має бути Прийнятий відповідь. Це ідеально. Тут усі умови виконані.
Nayan

1
За всіма голосовими відповідями ця відповідь справді працювала на мене.
Рохіт Мандіваль

Молодці! Я спробував всі комбінації і, здається, це чудово працює. Дякую.
akelec

Я не знаю, як це працює, але це просто працює як шарм.
wonsuc

17

Я домігся цього за допомогою TextWatcherнаступного способу

final EditText et = (EditText) findViewById(R.id.EditText1);
int count = -1;
et.addTextChangedListener(new TextWatcher() {
    public void onTextChanged(CharSequence arg0, int arg1, int arg2,int arg3) {             

    }
    public void beforeTextChanged(CharSequence arg0, int arg1,int arg2, int arg3) {             

    }

    public void afterTextChanged(Editable arg0) {
        if (arg0.length() > 0) {
            String str = et.getText().toString();
            et.setOnKeyListener(new OnKeyListener() {
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (keyCode == KeyEvent.KEYCODE_DEL) {
                        count--;
                        InputFilter[] fArray = new InputFilter[1];
                        fArray[0] = new InputFilter.LengthFilter(100);
                        et.setFilters(fArray);
                        //change the edittext's maximum length to 100. 
                        //If we didn't change this the edittext's maximum length will
                        //be number of digits we previously entered.
                    }
                    return false;
                }
            });
            char t = str.charAt(arg0.length() - 1);
            if (t == '.') {
                count = 0;
            }
            if (count >= 0) {
                if (count == 2) {                        
                    InputFilter[] fArray = new InputFilter[1];
                    fArray[0] = new InputFilter.LengthFilter(arg0.length());
                    et.setFilters(fArray);
                    //prevent the edittext from accessing digits 
                    //by setting maximum length as total number of digits we typed till now.
                }
                count++;
            }
        }
    }
});

Це рішення не дозволить користувачеві вводити більше двох знаків після десяткової крапки. Також ви можете ввести будь-яку кількість цифр перед десятковою комою. Дивіться цей блог http://v4all123.blogspot.com/2013/05/set-limit-for-fraction-in-decimal.html, щоб встановити фільтр для декількох EditText. Сподіваюся, це допоможе. Дякую.


Вибачте за пізню інформацію. Не забудьте ініціалізувати countз -1. Тоді тільки це буде працювати правильно. int count = -1;
Гунаселан

Gunaseelan - я спробував вищевказаний код та його добре працює. Але коли я видаляю набраний текст і знову набираю його, набираю лише одну цифру, будь-яке рішення для цього .....
Siva K

@SivaK Ні в якому разі не друг. Якщо ви видалите, а потім введіть, він прийме мінімум 100 цифр. Я не знаю, як ти до цього звертаєшся listener. Будь-який спосіб, будь ласка, подивіться мою публікацію в блозі . Ви можете отримати ідею. Якщо ви не можете, будь ласка, дайте мені знати. Я допоможу вам розглянути це питання.
Gunaseelan

я перевірив, що сказав @SivaK. це розумно в будь-якому випадку, але я збираюся внести деякі зміни до цього, щоб він був повністю функціональним (на мою думку)
MrTristan

@Gunaseelan дякую за ваше рішення. Але в ньому є деякі помилки. Наприклад, коли я видаляю другий десятковий знак, його неможливо знову ввести (я повинен видалити всі десяткові знаки, щоб мати можливість вводити його ще раз). Крім того, після видалення цілого запису при повторному введенні виникають деякі дивні обмеження.
akelec

14

Придуманий мною InputFilter дозволяє налаштувати кількість цифр до і після десяткового знака. Крім того, він відключає провідні нулі.

public class DecimalDigitsInputFilter implements InputFilter
{
    Pattern pattern;

    public DecimalDigitsInputFilter(int digitsBeforeDecimal, int digitsAfterDecimal)
    {
        pattern = Pattern.compile("(([1-9]{1}[0-9]{0," + (digitsBeforeDecimal - 1) + "})?||[0]{1})((\\.[0-9]{0," + digitsAfterDecimal + "})?)||(\\.)?");
    }

    @Override public CharSequence filter(CharSequence source, int sourceStart, int sourceEnd, Spanned destination, int destinationStart, int destinationEnd)
    {
        // Remove the string out of destination that is to be replaced.
        String newString = destination.toString().substring(0, destinationStart) + destination.toString().substring(destinationEnd, destination.toString().length());

        // Add the new string in.
        newString = newString.substring(0, destinationStart) + source.toString() + newString.substring(destinationStart, newString.length());

        // Now check if the new string is valid.
        Matcher matcher = pattern.matcher(newString);

        if(matcher.matches())
        {
            // Returning null indicates that the input is valid.
            return null;
        }

        // Returning the empty string indicates the input is invalid.
        return "";
    }
}

// To use this InputFilter, attach it to your EditText like so:
final EditText editText = (EditText) findViewById(R.id.editText);

EditText.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(4, 4)});

Приємне рішення! Це працює для мене, але я хочу відключити провідний період (крапка). Наприклад, ".123" не дозволена послідовність. Як цього досягти?
ібоголюбський

13

Вимога - 2 цифри після коми. Не повинно бути обмежень для цифр перед десятковою комою. Отже, рішення повинно бути,

public class DecimalDigitsInputFilter implements InputFilter {

    Pattern mPattern;

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

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

І використовувати його як

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

Дякуємо @Pinhassi за натхнення.


Добре ... Робоча штраф
Jojo

12

Моє рішення просте і працює ідеально!

public class DecimalInputTextWatcher implements TextWatcher {

private String mPreviousValue;
private int mCursorPosition;
private boolean mRestoringPreviousValueFlag;
private int mDigitsAfterZero;
private EditText mEditText;

public DecimalInputTextWatcher(EditText editText, int digitsAfterZero) {
    mDigitsAfterZero = digitsAfterZero;
    mEditText = editText;
    mPreviousValue = "";
    mRestoringPreviousValueFlag = false;
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    if (!mRestoringPreviousValueFlag) {
        mPreviousValue = s.toString();
        mCursorPosition = mEditText.getSelectionStart();
    }
}

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

@Override
public void afterTextChanged(Editable s) {
    if (!mRestoringPreviousValueFlag) {

        if (!isValid(s.toString())) {
            mRestoringPreviousValueFlag = true;
            restorePreviousValue();
        }

    } else {
        mRestoringPreviousValueFlag = false;
    }
}

private void restorePreviousValue() {
    mEditText.setText(mPreviousValue);
    mEditText.setSelection(mCursorPosition);
}

private boolean isValid(String s) {
    Pattern patternWithDot = Pattern.compile("[0-9]*((\\.[0-9]{0," + mDigitsAfterZero + "})?)||(\\.)?");
    Pattern patternWithComma = Pattern.compile("[0-9]*((,[0-9]{0," + mDigitsAfterZero + "})?)||(,)?");

    Matcher matcherDot = patternWithDot.matcher(s);
    Matcher matcherComa = patternWithComma.matcher(s);

    return matcherDot.matches() || matcherComa.matches();
}
}

Використання:

myTextEdit.addTextChangedListener(new DecimalInputTextWatcher(myTextEdit, 2));

Перемістіть шаблони з isValid()конструктора, щоб уникнути відтворення шаблонів на кожному isValid()дзвінку.
Гемант Каушик

6

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

Щось на зразок:

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

Редагувати - Немає вхідного типу для валюти, яку я міг би знайти в документах. Я думаю, це тому, що є деякі валюти, які не дотримуються того самого правила для десяткових знаків, як, наприклад, японська єна.

Як згадував LeffelMania, ви можете виправити введення користувача, скориставшись вищевказаним кодом, TextWatcherякий встановлений на вашому EditText.


6

Трохи вдосконалене рішення @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 "";
}

 }

6

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

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

}


Це майже те, що Reisub відповів на те саме запитання тут у 2014 році.
Мехул Джойсар

5
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 десяткових символи. Я думаю, що це досить простий спосіб зробити це.


4

Усі відповіді тут досить складні, я намагався зробити це набагато простіше. Подивіться на мій код і вирішуйте самі -

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

    }
});

це працює ідеально для мене. Я перевірив весь сценарій. Дякую.
Amarnath Baitha

Припустимо, я ввів 1234,56, тепер я хочу редагувати його так, як це 12378.56, я не можу це зробити, не видаляючи десятковий.
Аман Верма

4

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

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

4

Я покращив рішення, яке використовує регулярний вираз від Pinhassi, тому він також правильно обробляє крайові випадки. Перш ніж перевірити правильність введення, спочатку підсумковий рядок будується так, як описано в документах 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)});

4

Простий клас Helper тут, щоб запобігти введенню користувачем більше двох цифр після десяткових:

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

4

Я змінив відповідь №6 (автор Фавас Кв), бо там Ви можете поставити лише крапку на першій позиції.

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

Як говорили інші, я додав цей клас у свій проект і встановив фільтр на те, що 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.


Привіт, як я можу переконатися, що якщо користувач не введе десяткові (.), Він не повинен вводити більше двох цифр?
ManishNegi

2

Я також натрапив на цю проблему. Я хотів мати можливість повторно використовувати код у багатьох EditTexts. Це моє рішення:

Використання:

CurrencyFormat watcher = new CurrencyFormat();
priceEditText.addTextChangedListener(watcher);

Клас:

public static class CurrencyFormat implements TextWatcher {

    public void onTextChanged(CharSequence arg0, int start, int arg2,int arg3) {}

    public void beforeTextChanged(CharSequence arg0, int start,int arg2, int arg3) {}

    public void afterTextChanged(Editable arg0) {
        int length = arg0.length();
        if(length>0){
            if(nrOfDecimal(arg0.toString())>2)
                    arg0.delete(length-1, length);
        }

    }


    private int nrOfDecimal(String nr){
        int len = nr.length();
        int pos = len;
        for(int i=0 ; i<len; i++){
            if(nr.charAt(i)=='.'){
                pos=i+1;
                    break;
            }
        }
        return len-pos;
    }
}

2

@Meh для у ..

txtlist.setFilters(new InputFilter[] { new DigitsKeyListener( Boolean.FALSE,Boolean.TRUE) {

        int beforeDecimal = 7;
        int afterDecimal = 2;

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

            String etText = txtlist.getText().toString();
            String temp = txtlist.getText() + source.toString();
            if (temp.equals(".")) {
                return "0.";
            } else if (temp.toString().indexOf(".") == -1) {
                // no decimal point placed yet
                 if (temp.length() > beforeDecimal) {
                    return "";
                }
            } else {
                int dotPosition ;
                int cursorPositon = txtlistprice.getSelectionStart();
                if (etText.indexOf(".") == -1) {
                    dotPosition = temp.indexOf(".");
                }else{
                    dotPosition = etText.indexOf(".");
                }
                if(cursorPositon <= dotPosition){
                    String beforeDot = etText.substring(0, dotPosition);
                    if(beforeDot.length()<beforeDecimal){
                        return source;
                    }else{
                        if(source.toString().equalsIgnoreCase(".")){
                            return source;
                        }else{
                            return "";
                        }
                    }
                }else{
                    temp = temp.substring(temp.indexOf(".") + 1);
                    if (temp.length() > afterDecimal) {
                        return "";
                    }
                }
            }
            return super.filter(source, start, end, dest, dstart, dend);
        }
    } });

2

Дуже пізня відповідь: ми можемо зробити це просто так:

etv.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) {
            if (s.toString().length() > 3 && s.toString().contains(".")) {
                if (s.toString().length() - s.toString().indexOf(".") > 3) {
                    etv.setText(s.toString().substring(0, s.length() - 1));
                    etv.setSelection(edtSendMoney.getText().length());
                }
            }
        }

        @Override
        public void afterTextChanged(Editable arg0) {
        }
}

2

Ось те, TextWatcherщо допускає лише n число цифр після десяткових знаків.

TextWatcher

private static boolean flag;
public static TextWatcher getTextWatcherAllowAfterDeci(final int allowAfterDecimal){

    TextWatcher watcher = 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 count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            String str = s.toString();
            int index = str.indexOf ( "." );
            if(index>=0){
                if((index+1)<str.length()){
                    String numberD = str.substring(index+1);
                    if (numberD.length()!=allowAfterDecimal) {
                        flag=true;
                    }else{
                        flag=false;
                    }   
                }else{
                    flag = false;
                }                   
            }else{
                flag=false;
            }
            if(flag)
                s.delete(s.length() - 1,
                        s.length());
        }
    };
    return watcher;
}

Як використовувати

yourEditText.addTextChangedListener(getTextWatcherAllowAfterDeci(1));

Працює як шарм !!. Дякую
Хірен

2

Найпростіший спосіб досягти цього:

et.addTextChangedListener(new TextWatcher() {
    public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        String text = arg0.toString();
        if (text.contains(".") && text.substring(text.indexOf(".") + 1).length() > 2) {
            et.setText(text.substring(0, text.length() - 1));
            et.setSelection(et.getText().length());
        }
    }

    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {

    }

    public void afterTextChanged(Editable arg0) {
    }
});

Простий та досконалий відповідь
логотип

1

Ось моє рішення:

     yourEditText.addTextChangedListener(new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            NumberFormat formatter = new DecimalFormat("#.##");
            double doubleVal = Double.parseDouble(s.toString());
            yourEditText.setText(formatter.format(doubleVal));
        }

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

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

Якщо користувач вводить число з більш ніж двома цифрами після десяткової крапки, воно буде автоматично виправлене.

Я сподіваюся, що я допоміг!


Ви перевірили цей код? Насправді це не може працювати, тому що кожного разу, коли ви викликаєте setText (), TextWatcher знову запускається => нескінченний цикл.
muetzenflo

06-07 08: 01: 35.006: E / AndroidRuntime (30230): java.lang.StackOverflowError Не працює
Anjula

1

Це добре працює для мене. Це дозволяє вводити значення навіть після зміни фокусу та повернення назад. Наприклад: 123.00, 12.12, 0.01і т.д ..

1. Integer.parseInt(getString(R.string.valuelength)) Вказує довжину входу, digits.Valuesдо якого можна отримати доступ до string.xmlфайлу. Змінювати значення можна тихо і легко. 2. Integer.parseInt(getString(R.string.valuedecimal)), це максимальна межа для десяткових знаків.

private InputFilter[] valDecimalPlaces;
private ArrayList<EditText> edittextArray;

valDecimalPlaces = new InputFilter[] { new DecimalDigitsInputFilterNew(
    Integer.parseInt(getString(R.string.valuelength)),
    Integer.parseInt(getString(R.string.valuedecimal))) 
};

Масив EditTextзначень, що дозволяє виконувати дії.

for (EditText etDecimalPlace : edittextArray) {
            etDecimalPlace.setFilters(valDecimalPlaces);

Я просто використав масив значень, що містять кілька редакційних DecimalDigitsInputFilterNew.classфайлів Наступний файл.

import android.text.InputFilter;
import android.text.Spanned;

public class DecimalDigitsInputFilterNew implements InputFilter {

    private final int decimalDigits;
    private final int before;

    public DecimalDigitsInputFilterNew(int before ,int decimalDigits) {
        this.decimalDigits = decimalDigits;
        this.before = before;
    }

    @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("(([0-9]{1})([0-9]{0,"+(before-1)+"})?)?(\\.[0-9]{0,"+decimalDigits+"})?")) {
             if(source.length()==0)
                  return dest.subSequence(dstart, dend);
             return "";
        }
        return null;
    }
}

1

Це спирається на відповідь pinhassi - питання, на яке я зіткнувся, полягає в тому, що ви не можете додавати значення до десяткових знаків, коли буде досягнута десяткова межа. Щоб вирішити проблему, нам потрібно побудувати заключний рядок, перш ніж відповідати шаблону.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.text.InputFilter;
import android.text.Spanned;

public class DecimalLimiter implements InputFilter
{
    Pattern mPattern;

    public DecimalLimiter(int digitsBeforeZero,int digitsAfterZero) 
    {
        mPattern=Pattern.compile("[0-9]{0," + (digitsBeforeZero) + "}+((\\.[0-9]{0," + (digitsAfterZero) + "})?)||(\\.)?");
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) 
    {
        StringBuilder sb = new StringBuilder(dest);
        sb.insert(dstart, source, start, end);

        Matcher matcher = mPattern.matcher(sb.toString());
        if(!matcher.matches())
            return "";
        return null;
    }
}

1
et = (EditText) vw.findViewById(R.id.tx_edittext);

et.setFilters(new InputFilter[] {
        new DigitsKeyListener(Boolean.FALSE, Boolean.TRUE) {
            int beforeDecimal = 5, afterDecimal = 2;

            @Override
            public CharSequence filter(CharSequence source, int start, int end,
                    Spanned dest, int dstart, int dend) {
                String temp = et.getText() + source.toString();

                if (temp.equals(".")) {
                    return "0.";
                }
                else if (temp.toString().indexOf(".") == -1) {
                    // no decimal point placed yet
                    if (temp.length() > beforeDecimal) {
                        return "";
                    }
                } else {
                    temp = temp.substring(temp.indexOf(".") + 1);
                    if (temp.length() > afterDecimal) {
                        return "";
                    }
                }

                return super.filter(source, start, end, dest, dstart, dend);
            }
        }
});

Близько 2 років з часу вашої відповіді. Я спробував використати ваш код, тоді я виявив, що проблема щодо вашого рішення - це ви додаєте sourceпісля et.getText(). Завжди розуміється, що люди набирають у кінці поля замість початку поля. StringBuilder stringBuilder = new StringBuilder(text.getText().toString()); stringBuilder.replace(dstart, dend, source.toString()); String temp = stringBuilder.toString();повинен працювати. Все одно, дякую.
Truong Hieu

1

Створіть новий клас в Android kotlin з назвою DecimalDigitsInputFilter

class DecimalDigitsInputFilter(digitsBeforeZero: Int, digitsAfterZero: Int) : InputFilter {
lateinit var mPattern: Pattern
init {
    mPattern =
        Pattern.compile("[0-9]{0," + (digitsBeforeZero) + "}+((\\.[0-9]{0," + (digitsAfterZero) + "})?)||(\\.)?")
}
override fun filter(
    source: CharSequence?,
    start: Int,
    end: Int,
    dest: Spanned?,
    dstart: Int,
    dend: Int
): CharSequence? {
    val matcher: Matcher = mPattern.matcher(dest?.subSequence(0, dstart).toString() + source?.subSequence(start, end).toString() + dest?.subSequence(dend, dest?.length!!).toString())
    if (!matcher.matches())
        return ""
    else
        return null
}

Назвіть цей клас наступним рядком

 et_buy_amount.filters = (arrayOf<InputFilter>(DecimalDigitsInputFilter(8,2)))

відповідей занадто багато для того ж, але це дозволить вам ввести 8 цифр перед десятковою і 2 цифри після десяткових

інші відповіді приймають лише 8 цифр

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.