Androidの兵器庫にあるものを見て、この問題を解決しましょう。
要件から始めましょう。
基本的な要件:
- 指定された精度の数値のみを入力できる入力フィールドを実装します。
- 精度は、小数点の前後の有効桁数で指定されます。
追加要件:
- 入力カーソルのサポート。
- 標準の編集オプション:コピー、切り取り、貼り付け。
分析
Android
のコントロールの全範囲のうち、
EditText
ウィジェットに関心があります。
ドキュメントに目を向け、Android SDKが提供するものを確認します。
EditText
は
TextView
継承し、
TextView
には次のプロパティがあります。
XMLマークアップ
digits
-フィールドで使用できる特殊文字のセットを設定でき、数字入力モードを自動的にオンにします
numeric
入力ハンドラーを定義します。
inputType
定数値のセットを使用すると、目的の入力ハンドラーを生成できます。
パブリッククラスメソッド
setFilters
フィールドに値を入力するときに適用されるフィルターのセットを設定できます。
digits
、
numeric
、および
inputType
使用すると、入力文字のセットを制限できますが、
numeric
の精度には影響しませんが、
setFilters
だけが必要です。
実装
独自のフィルターを作成する前に、フィールドに数字と小数点記号のみを入力できるようにします。
numberEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
次に、指定された精度に対応する値のみを受け入れるように、入力フィールドに独自のフィルターを設定します。
InputFilter
インターフェースを実装し、具体的には
filter
メソッドを再定義する必要があります。
ドキュメントによると 、このメソッドは、dstartからdendの範囲の入力フィールド(dest)の値をstartからendの範囲のバッファー(ソース)のテキストで置き換えるときに呼び出されます。
上記を理解するための例
入力フィールドには123456(dest)、カーソルは1 [23] 456(dstart = 1、dend = 3)にあり、値789はバッファーから挿入されます(source = 789、start = 0、end 3)。
このメソッドは、現在の値の代わりに入力フィールドに設定される
CharSequence
クラスのオブジェクトを返します。 入力フィールドの値を置き換える必要がない場合は、メソッドで
null
を返す必要があり
null
。
小数点の前後の文字数をフィルターのコンストラクターに渡します。
フィルターコンストラクター
public NumberInputFilter(int digsBeforeDot, int digsAfterDot) { this.digsBeforeDot = digsBeforeDot; this.digsAfterDot = digsAfterDot; }
filter
メソッドを再定義し
filter
。 入力値をチェックするアルゴリズムは次のとおりです。
- 入力フィールドにバッファ値を配置する前に、この値を変数に挿入します。
- 取得した値が精度要件を満たしている場合、
null
を返すことで入力を許可しnull
。 - それ以外の場合は、空の文字列を返すため、入力値は破棄されます。
ユーザー入力後の将来価値を形成します。
便宜上、文字列を操作し、入力フィールドの初期値に基づいて
StringBuilder
クラスのインスタンスを作成し、入力値に基づいて必要な置換を行います。
StringBuilder newText = new StringBuilder(dest).replace(dstart, dend, source.toString());
その結果、
newText
変数にはテキストフィールドの将来の値が含まれます。
ここで、新しい値の正確さを確認する必要があります。
次の条件を満たす必要があります。
- 小数点の数は1を超えてはなりません。
123、123.45-true、12.3.4-不正解。 - 整数の文字数と数の小数部分は、指定された精度を満たしている必要があります。
区切り文字の数を確認しましょう。これのために、結果の文字列のすべての文字を反復処理します。
小数点記号がある場合は、そのインデックスを覚えておいてください。 区切り文字が再び見つかった場合、入力は正しくないとみなされ、サイクルが停止します。
小数点区切り検索
int size = newText.length(); int decInd = -1; // // // 1 for (int i = 0; i < size; i++) { if (newText.charAt(i) == '.') { if (decInd < 0) { decInd = i; // } else { // 1, isValid = false; break; } } }
数値自体の正確さを確認してください。 小数点区切り記号は既にわかっているか、欠落しています。
整数の長さをセパレータのインデックスと比較するためだけに残ります。
数値の精度を確認する
if (decInd < 0) { // if (size > integerSize) { // isValid = false; } } else if (decInd > digsBeforeDot) {// isValid = false; } else if (size - decInd - 1 > digsAfterDot) { // isValid = false; }
最後に結果を返します。
入力が正しい場合は
null
を返し、入力値を受け入れます。
そうでない場合は、入力フィールドに値を送信しないように空の文字列を返します。
if (isValid) { return null; } else { return ""; }
完全なソースコード@ github
デバッグ
私たちはプロジェクトを開始し、テストケースを紹介し、その境界を越えようとします。
テスト例として、番号123.45を使用します。 999.99より大きく0.01より小さい数値を入力することはできません。
映像

アプリケーションは、数値の整数部分と小数部分を正しく処理し、いくつかの小数点区切り文字の導入を禁止していることがわかります。
ただし、小数点区切り文字を削除すると、精度の境界を超える興味深い状況が観察されます。
これはドキュメントに記載されています。
長さ0の置換を拒否しないように注意してください。これは、テキストを削除するときに起こることです。
テキストを削除するときに起こるように、長さゼロの置換には注意する必要があります。
本当に何が起こったのですか?
アルゴリズムは正常に機能し、数値の整数部分の長さをチェックする条件下で、許容精度に違反していることを明らかにし、空の文字列を返しました。 ただし、文字削除アクション自体は、入力フィールドの元の値に適用されました。
この問題を次のように解決します-キャラクターの削除の事実を明らかにします。 ドキュメントは、この場合、長さゼロの置換が発生することを示唆しています。 入力フィールドの初期値から削除された文字を選択し、メソッドの結果としてそれらを返すことにより、削除を拒否します。
結果が返されるコードブロックを変更する必要があります
文字削除処理
if (isValid) { return null; } else if (source.equals("")) { // return dest.subSequence(dstart, dend); // } else { return ""; }
プロジェクトを開始して確認します。
映像

したがって、テストケースが完了し、目的の精度が達成されます。
ライブラリは実稼働で正常に使用されています。
Gradleを使用して接続できます
repositories { maven { url "https://raw.githubusercontent.com/hyperax/Android-NumberEditText/master/maven-repo" } } compile 'ru.softbalance.widgets:NumberEditText:1.1.2'
完全なプロジェクトソースコード@ github 。
ボーナス
多くの場合、入力フィールドのシステムキーボードの表示を無効にする必要があります。
たとえば、アプリケーションからキーボードを使用している場合。
Androidバージョン21以降で導入されたEditTextクラスメソッドが役に立ちます。
setShowSoftInputOnFocus(ブール表示)
実際、この方法は以前のバージョンにもありましたが、プライベートでした。
showSoftInputOnFocusCompat入力フィールドにメソッドを追加します
public void showSoftInputOnFocusCompat(boolean isShow){
showSoftInputOnFocus = isShow; if (Build.VERSION.SDK_INT >= 21) { setShowSoftInputOnFocus(showSoftInputOnFocus); } else { try { final Method method = EditText.class.getMethod("setShowSoftInputOnFocus", boolean.class); method.setAccessible(true); method.invoke(this, showSoftInputOnFocus); } catch (Exception e) { // ignore } } }
はい、これは「ハック」ですが、これは入力フィールドのシステムキーボードを非表示にする最も簡単で最短の方法です。