Android EditTextで小数点以下の桁数を制限する


125

私はあなたがあなたの財政を管理するのを助けるアプリを書こうとしています。EditTextユーザーが金額を指定できるフィールドを使用しています。

私はinputTypeto numberDecimalを適切に設定しましたが123.122、お金に最適でないような数値を入力できるようになっています。

小数点以下の文字数を2に制限する方法はありますか?


正規表現を記述して、フォーカスが外れたときにエディットテキストの内容を確認できます。
ブラインドスタッフ、2011年

私はInputFilterインターフェイスを見つけました、それは私がdeveloper.android.com/reference/android/text/method/…をしたいようですfilter私が実装しなければならないメソッドは私をかなり混乱させます。誰かがそのようなフィルターをすでに書いていて、それを使う方法を知っていましたか?
Konstantin Weitz

提案された解決策のいずれかが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
素晴らしいソリューションですが、完全に正しいわけではありません。マッチャーはdestをチェックするべきではありません。エディットテキストの値をチェックする必要があります(dest.subSequence(0、dstart)+ source.subSequence(start、end)+ dest.subSequence(dend、dest.length()))
Mihaela Romanca

7
ミハエラは正解です。edittextに入力しようとしている文字列と照合する必要があります。私はこのCharSequenceのような別の質問に連結する方法を見つけましたmatch = TextUtils.concat(dest.subSequence(0、dstart)、source.subSequence(start、end)、dest.subSequence(dend、dest.length())); 後で正規表現が問題を引き起こしていたので、これを "^ \\ d {1、" + digitsBeforeZero + "}(\\。\\ d {0、" + digitsAfterZero + "})?$"に変更しましたが、あなたは「1」のため、後で検証も行う必要があります。その正規表現では有効ですが、ピリオドを入力できるようにするためにそのようにする必要があります。
dt0 2014年

6
これをコンマ(、)でも機能させるにはどうすればよいでしょうか。世界の一部の地域では、カンマを使用して10進数を入力します(例: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」などの文字列に数字以外の文字を挿入できないのはなぜですか?
Konstantin Weitz

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

1
それは次のようになります:editText.setFilters(new InputFilter [] {new DecimalDigitsInputFilter(2)});
フラク2009

6
これは私が「999」と入力してから最初の9の後に小数点を挿入する場合は処理されません
ジェイク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です。

値のEditTextができること:555.25550.2

値というのEditTextブロック:55555.2055.2555.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およびdigitsafter = 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 2016年

1
@Omkarこれは間違っています。この条件は...長さ> 0、dest.lengthは()== 0は、常にあなたがより0よりもテキスト全体を真EDITTEXT場合でもあっても常にtrueになります
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 = "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
乾杯。仕事は非常によく、他のは私のために動作しませんでしたとき
ベア

1
これは受理された答えであるはずです。それは完璧です。すべての条件がここで満たされています
ナヤン

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

このソリューションでは、ユーザーは小数点の後に2桁以上を入力できません。また、小数点の前に任意の桁数を入力できます。複数のEditTextにフィルターを設定するには、このブログhttp://v4all123.blogspot.com/2013/05/set-limit-for-fraction-in-decimal.htmlを参照してください。これがお役に立てば幸いです。ありがとうございました。


遅い情報でごめんなさい。で初期化countすることを忘れないでください-1。次に、これだけが正しく動作します。int count = -1;
Gunaseelan 2013年

Gunaseelan-上記のコードを試してみましたが、うまく機能しました。しかし、入力したテキストを削除してもう一度入力を開始すると、1桁しか入力できなくなります。これに対する解決策は.....
Siva K

@SivaKまさか友達。削除してから入力すると、100桁以上が受け入れられます。どうやってこれにアクセスするのかわかりませんlistener。とにかく私のブログ投稿を見てください。あなたはアイデアを得るかもしれません。できない場合はお知らせください。この問題について、私がお手伝いします。
Gunaseelan 2013年

@SivaKの発言を確認しました。これはどんな場合でも賢いですが、完全に機能するようにこれをいくつか編集します(私の意見では)
MrTristan

@Gunaseelan解決策をありがとうございます しかし、それはいくつかのバグがあります。たとえば、2番目の10進数を削除すると、再度入力することは不可能です(もう一度入力できるようにするには、すべての10進数を削除する必要があります)。また、エントリ全体を削除した後、もう一度入力するといくつかの奇妙な制限が発生します。
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」はシーケンスとして使用できません。これを達成する方法は?
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()を使用して、文字列をTextViewに入れる前にフォーマットしてみてください。

何かのようなもの:

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

編集 -私がドキュメントで見つけることができる通貨のinputTypeはありません。これは、日本円など、小数点以下で同じルールに従わない通貨があるためだと思います。

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年にここに同じ質問に答えたものはほとんどあり
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 2017

1234.56と入力したとしましょう。今、この12378.56のように編集したいのですが、小数点を削除しないと編集できません。
Aman Verma

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 docsの説明に従って作成されます。

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

シンプルヘルパークラスは、ユーザーが10進数の後に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を変更しました(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()});

ここで重要なことの1つは、小数点以下2桁以上を表示できないという私の問題を解決します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


こんにちは、ユーザーがdecimal(。)を入力しない場合、2桁を超えて入力できないようにするにはどうすればよいですか?
ManishNegi 2017

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

以下は、小数点以下nTextWatcherのみを許可するものです。

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

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

Simple and Perferct Answer
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) {}
    });

ユーザーが小数点の後に3つ以上の数字を入力すると、自動的に修正されます。

私は助けてくれたことを願っています!


このコードをテストしましたか?setText()を呼び出すたびにTextWatcherが再度起動するため、実際には機能しません=>無限ループ。
muetzenflo 2013

06-07 08:01:35.006:E / AndroidRuntime(30230):java.lang.StackOverflowError機能していません
Anjula

1

これでうまくいきます。フォーカスが変更されて戻った後でも、値を入力できます。たとえば、次のように123.0012.120.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 Next 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

これはピニャッシの答えに基づいています-私が遭遇した問題は、小数の制限に達した後、小数の前に値を追加できないことでした。この問題を修正するには、パターンマッチを実行する前に最終的な文字列を作成する必要があります。

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 2017

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

同じ答えが多すぎますが、10進数の前に8桁、10進数の後に2桁を入力できます。

他の回答は8桁のみを受け入れます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.