EditText金額輸入(限制輸入金額大小和小數點后兩位)
標簽(空格分隔): Android開發
Android中控制EditText輸入內容、長度的方法有三種
-
方案一:
- 通過監聽EditText的addTextChangedListener方法
-
方案二:通過setFilter()方法設置過濾器
- 也就是自定義一個類實現InputFilter接口,復寫filter這個方法在里面進行相關邏輯
-
方案三:通過布局文件中,控件的屬性來控制
- 例如 maxLength、inputType、minLength等
需求
最近在開發app的時候,收到了這樣的需求,也就是打賞金額,用戶可以自定義金額,并且需要用戶輸入的金額不能大于500并且限制小數點后兩位小數,也就是最多輸入499.99元。那么這個只能自己自定義了。可以看到,這個需求以上的三種方式,第三種并不能達到這樣的邏輯要求,暫時排除,也就是只有方案一和方案二了.
關于google為啥有這樣的三種方式控制EditText相關操作,可以查看這個InputFilter詳解、TextWatcher詳解 所以接下來可以給出最終的一個實現方案,那就是實現InputFilter接口重寫filter這個方法來實現上述需求。
給出方案
在方案代碼開始之前,我們需要先了解一下filter方法的各個參數的含義:
CharSequence filter (CharSequence source,
int start,
int end,
Spanned dest,
int dstart,
int dend)
參數簡介
- source 新輸入的字符串
- start 新輸入的字符串起始下標,一般為0
- end 新輸入的字符串終點下標,一般為source長度-1
- dest 輸入之前文本的內容
- dstart 原內容起始坐標 一般為0
- dend 原內容終點坐標,一般為dest長度-1
可以看出我們可以獲取到原本輸入的字符串,還有我們即將輸入的字符串,然后關于光標所在的位置(可以的出來的),而且我們還可以得到原字符串和即將輸入字符串的起始坐標,那么我們就來搞事情吧。廢話不多說,直接上代碼
/**
* Created by ruolanmingyue on 2017/10/26.
*
* @function 用于過濾輸入 防止輸入大于500元還有就是限制小數點之后兩位
*/
public class EditInputFilter implements InputFilter {
/**
* 最大數字
*/
public static final int MAX_VALUE = 500;
/**
* 小數點后的數字的位數
*/
public static final int POINTER_LENGTH = 2;
private static final String POINTER = ".";
Pattern p;
public EditInputFilter() {
//用于匹配輸入的是0-9 . 這幾個數字和字符
p = Pattern.compile("([0-9]|\\.)*");
}
/**
* source 新輸入的字符串
* start 新輸入的字符串起始下標,一般為0
* end 新輸入的字符串終點下標,一般為source長度-1
* dest 輸入之前文本框內容
* dstart 原內容起始坐標,一般為0
* dend 原內容終點坐標,一般為dest長度-1
*/
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
String sourceText = source.toString();
String destText = dest.toString();
//驗證刪除等按鍵
if (TextUtils.isEmpty(sourceText)) {
if (dstart == 0 && destText.indexOf(POINTER) == 1) {//保證小數點不在第一個位置
return "0";
}
return "";
}
Matcher matcher = p.matcher(source);
//已經輸入小數點的情況下,只能輸入數字
if (destText.contains(POINTER)) {
if (!matcher.matches()) {
return "";
} else {
if (POINTER.equals(source)) { //只能輸入一個小數點
return "";
}
}
//驗證小數點精度,保證小數點后只能輸入兩位
int index = destText.indexOf(POINTER);
int length = destText.trim().length() - index;
if (length > POINTER_LENGTH && dstart > index) {
return "";
}
} else {
//沒有輸入小數點的情況下,只能輸入小數點和數字,但首位不能輸入小數點和0
if (!matcher.matches()) {
return "";
} else {
if ((POINTER.equals(source)) && dstart == 0) {//第一個位置輸入小數點的情況
return "0.";
} else if ("0".equals(source) && dstart == 0) {
return "";
}
}
}
// dstart
//修復當光標定位到第一位的時候 還能輸入其他的 這個是為了修復以下的情況
/**
* <>
* 當如下情況的時候 也就是 已經輸入了23.45 這個時候限制是500元
* 那么這個時候如果把光標移動2前面 也就是第0位 在輸入一個5 那么這個實際的參與下面的
* 判斷的sumText > MAX_VALUE 是23.455 這個是不大于 500的 但是實際情況是523 這個時候
* 已經大于500了 所以之前的是存在bug的 這個要進行修正 也就是拿到的比較數應該是523.45 而不是23.455
* 所以有了下面的分隔 也就是 把23.45 (因為這個時候dstart=0) 分隔成 "" 和23.45 然后把 5放到中間
* 進行拼接 也就是 "" + 5 + 23.45 也就是523.45 然后在進行和500比較
* 還有一個比較明顯的就是 23.45 這個時候光標在2和3 之間 那么如果修正之前 是23.455 修正之后 dstart = 1
* 這個時候分隔是 "2" "3.45" 這個時候拼接是253.45 然后和500比較 以此類推
* </>
*/
String first = destText.substring(0,dstart);
String second = destText.substring(dstart,destText.length());
// dend
String sum = first + sourceText + second;
//驗證輸入金額的大小
double sumText = Double.parseDouble(sum);
//這里得到輸入完之后需要計算的金額 如果這個金額大于了事先設定的金額,那么久直接返回 不需要加入輸入的字符
if (sumText > MAX_VALUE) {
//
Toast.makeText(MyApp.getContext(), MyApp.getContext().getResources().getString(R.string.appreciate_input), Toast.LENGTH_SHORT).show();
return dest.subSequence(dstart, dend);
}
//如果輸入的金額小于事先規定的金額
return dest.subSequence(dstart, dend) + sourceText;
}
}
使用方式
EditText editText = new EditText(getContext());
InputFilter[] filters = {new EditInputFilter()};
editText.setFilters(filters);
參考文檔
-
Android實現EditText輸入金額
- 但是這個文章寫的有bug,發現的bug如下兩個
- 1、輸入金額之后,當手動改edittext里面的光標的時候,比如剛開始輸入的是23.22元,這個時候把光標移動到2和3之間,那么我們還可以輸入2223.22元,也就是不符合不能大于500元需求,這個在上面的說明中有詳細的說明
- 2、當改動光標在.后面的時候,也是可以說入數字的,也就是不符合輸入數字限制兩位小數要求
- 但是這個文章寫的有bug,發現的bug如下兩個