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