Android EditText에서 소수 자릿수 제한


125

재정 관리에 도움이되는 앱을 작성하려고합니다. EditText사용자가 금액을 지정할 수 있는 필드를 사용하고 있습니다.

나는 사람들이 돈에 적합하지 않은 숫자를 입력 할 수 있다는 점을 제외하고는 잘 작동 하는 inputType것으로 설정했습니다 .numberDecimal123.122

소수점 뒤의 문자 수를 2로 제한하는 방법이 있습니까?


정규식을 작성하고 포커스를 잃을 때 편집 텍스트의 내용을 확인할 수 있습니다.
blindstuff 2011 년

내가 찾은 InputFilter이 내가 원하는 일을 할 것, 인터페이스를 developer.android.com/reference/android/text/method/... 하지만 방법 filterI가 구현해야하는 것이 오히려 나에게 혼란된다. 누군가 이미 그러한 필터를 작성했고 사용 방법을 알고 있습니까?
Konstantin Weitz 2011 년

RTL 로케일에 대해 제안 된 솔루션이 작동합니까? 내가 말할 수있는 한 그들은 그렇게하지 않을 것입니다 ...
Nick

답변:


118

더 우아한 방법은 다음과 같이 정규식 (regex)을 사용하는 것입니다.

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
사용자가 소수점 뒤에 2 자리를 입력 한 후에는 소수점 이하 자리를 변경할 수 없습니다.
Gaurav Singla 2013

9
훌륭한 솔루션이지만 완전히 정확하지는 않습니다. matcher는 dest를 확인해서는 안되며 edittext의 값을 확인해야합니다 (dest.subSequence (0, dstart) + source.subSequence (start, end) + dest.subSequence (dend, dest.length ()))
Mihaela Romanca

7
Mihaela가 맞습니다. 우리는 편집 텍스트를 채우려는 문자열과 일치해야합니다. 이 CharSequence match = TextUtils.concat (dest.subSequence (0, dstart), source.subSequence (start, end), dest.subSequence (dend, dest.length ()));와 같은 다른 질문에 연결하는 방법을 찾았습니다. 하지만 정규식은 나중에 문제를 일으키고 있었기 때문에 "^ \\ d {1,"+ digitBeforeZero + "} (\\. \\ d {0,"+ digitAfterZero + "})? $"로 변경했습니다. "1"이기 때문에 나중에 유효성 검사를해야합니다. 해당 정규식에 유효하지만 마침표를 입력 할 수 있도록 그렇게해야합니다.
dt0 2014

6
쉼표 (,)에 대해서도 어떻게 작동합니까? 세계의 일부 지역은 쉼표가있는 십진수를 입력합니다 (예 : 123,45).
Andrew

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'와 같은 문자열에 숫자가 아닌 문자를 삽입하지 못하게하는 이유는 무엇입니까?
Konstantin Weitz 2011 년

4
이 : <EditText ... android : inputType = "number"/>
peceps

1
다음과 같아야합니다. editText.setFilters (new InputFilter [] {new DecimalDigitsInputFilter (2)});
frak

6
이것은 내가 "999"를 입력 한 다음 첫 번째 9 뒤에 소수점을 삽입하는 경우를 처리하지 않습니다.
Jake Stoeffler

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

null 대신 SpannableStringBuilder를 반환해야하는 이유가 있는지 알 수 있나요? 나는 null로 테스트하고 잘 작동합니다. 또한 DigitsKeyListener에서 상속 할 필요가 있습니까? android : inputType = "numberDecimal"을 사용하면 "0123456789"를 모두 수행합니다. 문자 시행.
Cheok Yan Cheng

1
잘 작동합니다. 대단히 감사합니다.
Andrei Aulaska 2013

34

다음은 소수점 앞 최대 4 자리와 그 이후 최대 1 자리 만 허용 하는 샘플 InputFilter 입니다.

값 글고 치기는 허용 : 555.2 , 555 , 0.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. 마이너스 기호 처리

3.digitsbefore = 2 및 numbersafter = 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 "";
    }
}

완벽한 솔루션이어야한다고 생각합니다. 감사합니다.
Pratik Butani

1
@Omkar 이것은 잘못되었습니다. 이 조건은 길이> 0 인 경우에도 항상 참이고, dest.length () == 0 텍스트 전체 텍스트를 0보다 큰 값으로 편집하더라도 항상 참 ...
user924

귀하의 코멘트 PLS 제거 @Omkar
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 = "numberDecimal"

  2. onCreate에 리스너를 추가하십시오. 점 편집 전후의 자릿수를 수정하려면 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
건배. 다른 사람이 나를 위해 일하지 않았을 때 아주 잘 작동합니다
Bear

1
이것은 받아 들여진 대답이어야합니다. 완벽합니다 .. 여기에서 모든 조건이 충족됩니다.
Nayan

1
투표율이 높은 모든 답변 에서이 답변은 실제로 저에게 효과적이었습니다.
Rohit Mandiwal

잘 했어! 나는 모든 조합을 시도했고 그것이 잘 작동하는 것 같습니다. 감사합니다.
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++;
            }
        }
    }
});

이 솔루션은 사용자가 소수점 뒤에 두 자리 이상을 입력하는 것을 허용하지 않습니다. 또한 소수점 앞에 임의의 자릿수를 입력 할 수 있습니다. 여러 EditText에 대한 필터를 설정하려면 http://v4all123.blogspot.com/2013/05/set-limit-for-fraction-in-decimal.html 블로그를 참조하십시오 . 이것이 도움이되기를 바랍니다. 감사합니다.


늦은 정보로 죄송합니다. 로 초기화 count하는 것을 잊지 마십시오 -1. 그러면 이것 만 올바르게 작동합니다. int count = -1;
Gunaseelan 2013 년

Gunaseelan-위의 코드와 그 작동을 시도했습니다. 하지만 입력 한 텍스트를 삭제하고 다시 입력하기 시작하면 한 자리 만 입력하면이 문제에 대한 해결책이 있습니다 .....
Siva K

@SivaK 안돼 친구. 삭제 후 입력하면 최소 100 자리를 허용합니다. 나는 당신이 이것에 어떻게 액세스하고 있습니까 listener? 어쨌든 내 블로그 게시물을 봐주세요 . 아이디어를 얻을 수 있습니다. 할 수 없다면 알려주세요. 이 문제에 대해 도와 드리겠습니다.
Gunaseelan 2013-06-05

@SivaK가 말한 것을 확인했습니다. 이것은 어떤 경우에도 영리하지만 완전히 기능하도록 (제 의견으로는) 약간 편집 할 것입니다
MrTristan

@Gunaseelan 귀하의 솔루션에 감사드립니다. 그러나 몇 가지 버그가 있습니다. 예를 들어 두 번째 소수점을 삭제하면 다시 입력 할 수 없습니다 (다시 입력하려면 소수점을 모두 삭제해야합니다). 또한 전체 항목을 삭제 한 후 다시 입력하면 이상한 제한이 발생합니다.
akelec

14

내가 생각 해낸 InputFilter를 사용하면 소수점 이하 자릿수를 구성 할 수 있습니다. 또한 선행 0을 허용하지 않습니다.

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"은 허용되지 않는 시퀀스입니다. 이것을 달성하는 방법?
ibogolyubskiy

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에게 감사드립니다.


좋은 ... 작업 벌금
조조

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()호출 에서 패턴이 다시 생성되지 않도록 패턴 을 생성자로 이동합니다 .
Hemant Kaushik

6

사용해보십시오 NumberFormat.getCurrencyInstance ()를 사용하면 텍스트 뷰에 넣어 전에 문자열을 포맷 할 수 있습니다.

다음과 같은 것 :

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

편집 -문서에서 찾을 수있는 통화에 대한 inputType이 없습니다. 일본 엔과 같이 소수 자리에 대해 동일한 규칙을 따르지 않는 일부 통화가 있기 때문이라고 생각합니다.

LeffelMania가 언급했듯이 .NET Framework 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 년에 여기에 같은 질문에 대답 것을 거의이다
Mehul Joisar

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과 같이 편집하고 싶습니다. 소수점을 삭제하지 않고는 할 수 없습니다.
Aman Verma

4

나는 Pinhassi의 대답을 정말 좋아했지만 사용자가 소수점 뒤에 지정된 숫자를 입력 한 후에는 더 이상 소수점 왼쪽에 텍스트를 입력 할 수 없다는 것을 알았습니다. 문제는 솔루션이 현재 입력중인 텍스트가 아니라 이전에 입력 된 텍스트 만 테스트한다는 것입니다. 그래서 여기에 유효성 검사를 위해 새 문자를 원본 텍스트에 삽입하는 솔루션이 있습니다.

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

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

4

나는 대답 №6 (by 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

다른 사람들이 말했듯이 프로젝트에이 클래스를 추가하고 필터를 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을 반환합니다.

그래서 .NET에서 가져온 값을 다시 파싱해야했습니다 EditText.

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

setScale에서 전체 텍스트를 가져온 후 여기에서 트릭을 수행합니다 EditText.


안녕하세요, 사용자가 소수점 (.)을 입력하지 않았는지 확인하려면 어떻게해야합니까? 2 자리 이상을 입력 할 수 없습니다.
ManishNegi

2

나는 또한이 문제를 발견했습니다. 나는 많은 EditText에서 코드를 재사용 할 수 있기를 원했습니다. 이것이 내 해결책입니다.

사용법 :

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 for u ..

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

다음은 소수점 이하 n 자리 TextWatcher만 허용 하는 것 입니다 .

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

매력처럼 작동 !!. 감사합니다 Hiren :)
nisha.113a5

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

간단하고 정확한 답변
Logo

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

사용자가 소수점 뒤에 2 개 이상의 숫자를 입력하면 자동으로 수정됩니다.

도움이 되었기를 바랍니다.


이 코드를 테스트 했습니까? 실제로 작동하지 않습니다. 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)) 한 입력의 길이를 지정 합니다. 값을 변경하는 것은 조용합니다. 2. , 소수점 이하 최대 한계입니다.digits.Valuesstring.xmlInteger.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);

여러 개의 edittext 다음 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 년. 그때 내가 솔루션에 대한 문제가 당신이 추가입니다 발견 코드를 사용하려고 sourceet.getText(). 사람들이 상자의 시작이 아닌 상자 끝에 입력하는 것을 항상 이해합니다. StringBuilder stringBuilder = new StringBuilder(text.getText().toString()); stringBuilder.replace(dstart, dend, source.toString()); String temp = stringBuilder.toString();작동합니다. 어쨌든 감사합니다.
의 Truong Hieu

1

DecimalDigitsInputFilter라는 이름으로 Android kotlin에서 새 클래스를 만듭니다.

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 자리 만받습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.