看慣了可能是XXX最好的,可能是XXXX目前最好的矢否,今天我也用下這個標題,哈哈脑溢。別噴我僵朗,當然我也就吹吹牛。有很多好的方法來實現(xiàn)屑彻。
本文主要還是用來講解下InputFilter的使用验庙。
一般金額類的輸入需求比較多,我們這里就用金額輸入框做實例社牲。其他的類似的文字粪薛,大小寫字母等需求限制也是同理的。
某天產(chǎn)品經(jīng)理 A拿著菜刀到我身邊說:
第一次交鋒
A:小B啊搏恤,這個界面的金額輸入框輸入的錢小數(shù)點后最多二位违寿,也就是最多到分,還有那個界面的這個地方熟空,填金額也是精度到分藤巢。
唯唯諾諾的我:好的,馬上完成息罗。
1.控制小數(shù)點后位數(shù):
因為有很多界面都要用到掂咒,所以我們專門抽出一個類來進行控制,并且我們知道迈喉,我們要控制EditText控制它的輸入內(nèi)容绍刮,其實相當于是對其進行過濾,所以我們讓我們的類實現(xiàn)InputFilter
接口挨摸。
public class PointLengthFilter implements InputFilter {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
return null;
}
}
發(fā)現(xiàn)一定要我們實現(xiàn)filter
方法,從字面意思看我們也知道是過濾孩革,那我們來看下具體的參數(shù)字段的意思:
字段 |類型 | 內(nèi)容
-------|-----------|-------------|-------------
source | CharSequence | 為即將輸入的字符串
start | int | source的start, start 為0
end | int | source的end ,因為start為0油坝,end也可理解為source長度了
dest | Spanned|輸入框中原來的內(nèi)容
dstart | int | 要替換或者添加的起始位置嫉戚,即光標所在的位置
dend | int | 要替換或者添加的終止始位置刨裆,若為選擇一串字符串進行更改,則為選中字符串 最后一個字符在dest中的位置
我們來假設下彬檀,我們通過鍵盤依次輸入12345帆啃,我們可以看到相應的值:
source:1,start:0,end:1,dest:,dstart:0,dend:0
source:2,start:0,end:1,dest:1,dstart:1,dend:1
source:3,start:0,end:1,dest:12,dstart:2,dend:2
source:4,start:0,end:1,dest:123,dstart:3,dend:3
source:5,start:0,end:1,dest:1234,dstart:4,dend:4
大家可能會發(fā)現(xiàn)start一直為0,end一直為1窍帝,因為我們是依次輸入的努潘,比如你復制三個字符,通過粘貼復制的方式加入到EditText中坤学,這時候就不是0和1了疯坤,而是0,3。
所以根據(jù)這個小數(shù)點位數(shù)需求深浮,我們先來第一版的Filter
(有問題版本)
public class PointLengthFilter implements InputFilter {
private static final int DECIMAL_DIGITS = 2;//小數(shù)的位數(shù)
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// 刪除等特殊字符压怠,直接返回
if ("".equals(source.toString())) {
return null;
}
//原來輸入框已有的內(nèi)容
String dValue = dest.toString();
//通過小數(shù)點來進行拆分,分為小數(shù)點前面的字符串和小數(shù)點后面的字符串
String[] splitArray = dValue.split("\\.");
if (splitArray.length > 1) {
//獲的小數(shù)點后面的字符串
String dotValue = splitArray[1];
//判斷小數(shù)點后面的當前位數(shù)是不是已經(jīng)大于等于規(guī)定的2了
//如果已經(jīng)2位了飞苇,則返回"";
if (dotValue.length() >= DECIMAL_DIGITS) {
return "";
}
}
return null;
}
}
然后在我們的Activity中設置:
EditText editText = (EditText) findViewById(R.id.et_money);
editText.setFilters(new InputFilter[]{new PointInputFilter()});
PS :可以把過濾的條件單獨寫出來分為好幾個文件菌瘫,因為傳入的是InputFilter數(shù)組。
這樣布卡。我們終于實現(xiàn)了小數(shù)點后面的位數(shù)控制了雨让。
如下圖所示,我們輸入12345.67之后忿等,再輸入其他字符栖忠,在filter中就默認返回了一個空的字符串"",所以就等于沒輸入其他內(nèi)容進去。
第二次交鋒:
產(chǎn)品經(jīng)理 A拿著菜刀氣沖沖的過來了贸街。
A:你這個輸入金額的有問題你知道嗎庵寞?你都不能自己好好測試測試嗎?
低聲下氣的我:不可能啊薛匪,我測試過的啊皇帮,小數(shù)點后面的數(shù)的位數(shù)不會超過2啊。
A:位數(shù)的確不超過2了蛋辈,但是你修改下小數(shù)點前面的數(shù)字試試属拾。
我拿著手機試了下,比如上面我們已經(jīng)輸入了12345.67冷溶,這時候我想在小數(shù)點前面的內(nèi)容多加個數(shù)字渐白,或者前面的12345我刪了幾個,再輸入其他數(shù)字都不行了逞频。因為小數(shù)點后的位數(shù)是一直是2纯衍,這時候我們修改小數(shù)點前的內(nèi)容,就一直觸發(fā):
String[] splitArray = dValue.split("\\.");
if (splitArray.length > 1) {
//獲的小數(shù)點后面的字符串
String dotValue = splitArray[1];
//判斷小數(shù)點后面的當前位數(shù)是不是已經(jīng)大于等于規(guī)定的2了
//如果已經(jīng)2位了苗胀,則返回"";
if (dotValue.length() >= DECIMAL_DIGITS) {
return "";
}
}
所以一直返回一個空字符串襟诸,所以就無法修改小數(shù)點前面的數(shù)字了瓦堵。
2.控制小數(shù)點位數(shù)的同時,更改小數(shù)點前的數(shù)字:
我們只需要改原本控制小數(shù)點的邏輯代碼即可:
String dValue = dest.toString();
String[] splitArray = dValue.split("\\.");
if (splitArray.length > 1) {
String dotValue = splitArray[1];
//獲取小數(shù)點“.”在字符串中的index值
int dotIndex = dValue.indexOf(".");
/添加了一個條件判斷:輸入光標是在小數(shù)點的后面
if (dotValue.length() >= DECIMAL_DIGITS && dstart > dotIndex) {
return "";
}
}
試了一下歌亲。果然可以自由的對小數(shù)點前面的數(shù)字隨意的增刪改了菇用。哈哈。我心滿意足的再次改好上交了陷揪。
第三次交鋒:
產(chǎn)品經(jīng)理這次拿著一把砍刀再次過來惋鸥。
A:你這個輸入金額的小數(shù)點前面的數(shù)可以輸入很多,我這邊考慮了下悍缠,要求小數(shù)點前面最多輸入6位卦绣,加起來最大可輸入的值是999999.99元。也就是不超過一百萬飞蚓,下班前記得完成哦滤港。
有點氣憤的我:好的。包您滿意趴拧。
3.限制小數(shù)點前面的位數(shù):
這時候其實我們也知道并不難蜗搔,只要在小數(shù)點前面的位數(shù)增加控制就行:
public class PointInputFilter1 implements InputFilter {
private static final int DECIMAL_DIGITS = 2;//小數(shù)的位數(shù)
private static final int INTEGER_DIGITS = 6;//整數(shù)位的位數(shù)
private static final int TOTAL_DIGITS = 9; //整數(shù)部分 + “小數(shù)點” + 小數(shù)部分
private int currentLimitDigits = INTEGER_DIGITS;//當前控制的位數(shù)值
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// 刪除等特殊字符,直接返回
if ("".equals(source.toString())) {
return null;
}
String dValue = dest.toString();
String[] splitArray = dValue.split("\\.");
switch (splitArray.length) {
case 1:
//判斷當前是否有小數(shù)點八堡,如果有小數(shù)點就把控制位數(shù)變?yōu)門OTAL_DIGITS(其實只要比整數(shù)位數(shù)+1大就可以)
if (dValue.indexOf(".") != -1) {
currentLimitDigits = TOTAL_DIGITS;
} else {
//如果沒有小數(shù)點,則繼續(xù)控制前面整數(shù)位的位數(shù)為6位
currentLimitDigits = INTEGER_DIGITS;
}
/**這里如果我們直接輸入999999時候聘芜,其實已經(jīng)不能按其他數(shù)字了兄渺,
不然就超過一百萬了,但是這時候如果輸入的是小數(shù)點汰现,則可以在輸入框中顯示小數(shù)點挂谍。
而且這時候在上面已經(jīng)把當前的位數(shù)限制變大,
這時候就可以就可以輸入其他數(shù)字瞎饲,然后接下去就會跳入到下面的case 2的判斷了口叙。
**/
if(splitArray[0].length() >= currentLimitDigits && !".".equals(source.toString())){
return "";
}
break;
case 2:
String integerValue = splitArray[0];
String dotValue = splitArray[1];
int dotIndex = dValue.indexOf(".");
if (integerValue.length() >= INTEGER_DIGITS && dstart <= dotIndex) {
return "";
}
if (dotValue.length() >= DECIMAL_DIGITS && dstart > dotIndex) {
return "";
}
break;
default:
break;
}
return null;
}
}
這下終于可以交差了。然后沾沾自喜的把成果發(fā)布了一版嗅战,開心的等著下班妄田。
第四次交鋒:
產(chǎn)品經(jīng)理推著大炮再次走了過來,
A:你的輸入有問題驮捍,你看疟呐,我都輸入了好幾百萬了。
我:不可能啊东且,我測試過的啊启具,我演示給你看,看吧珊泳。不可能輸?shù)眠M去的鲁冯。
A:我不是鍵盤輸入的拷沸,我是直接其他地方復制了多位數(shù)字,然后粘貼復制進去的薯演。
我: ........
A:反正我不管撞芍,你沒弄完不準下班。
我心里暗暗說了句:MMP
4.處理通過粘貼復制的方式輸入
這里我們可以有二種處理方式:
- 直接就干脆不讓多位數(shù)字粘貼進來涣仿。
- 針對多位數(shù)字賦值粘貼來進行處理勤庐。
<1> 不準復制粘貼多位數(shù)字:
這個很簡單,如果客戶是復制一位數(shù)字好港,然后粘貼復制進去的愉镰,其實就等效我們用鍵盤輸入,所以就不需要特殊處理钧汹。我們只在意的是比如現(xiàn)在是999.99丈探,他在前面直接粘貼了99999。就變成了99999999.99了拔莱,超過我們的范圍了碗降。我們可以直接禁止多位數(shù)字的粘貼復制,代碼很簡單:
//在最前面多添加一個判斷塘秦,就是當輸入的字符是多位的時候讼渊,直接返回空字符串。
//因為通過鍵盤輸入我們都是一位位輸入的尊剔,而多位的情況一般就是復制粘貼進來的爪幻。
if(source.length() > 1){
return "";
}
<2> 處理粘貼復制的方式的輸入:
我們假設這幾種情況:
(1)輸入框里面的內(nèi)容是整數(shù),比如1234须误,然后我們復制整數(shù)9999進去挨稿,這時候應該是123499。
(2)輸入框里面的內(nèi)容是整數(shù)京痢,比如1234奶甘,然后我們復制整數(shù)999.999進去,這時候應該是123499.99祭椰。
(3)輸入框里面的內(nèi)容是小數(shù)臭家,比如1234.1,然后我們復制整數(shù)999進去方淤,如果復制在小數(shù)點前面侣监,應該是123499.1,如果復制在小數(shù)點后面臣淤,應該是1234.1橄霉。
(4)輸入框里面的內(nèi)容是小數(shù),比如1234.1,然后我們復制的也是小數(shù)進去姓蜂,比如9.9按厘,我們粘貼在小數(shù)點前,則變?yōu)榱?23499.1钱慢,因為輸入框內(nèi)默認就一個小數(shù)點逮京,復制進來的9.9我們就作為99加入到整數(shù)部分。如果加到小數(shù)點后面則變?yōu)?234.19束莫。
(5)輸入框里面是空的內(nèi)容懒棉,我們輸入12345678.87654321;小數(shù)點前面也超出览绿,后面也超出策严,取有效部分澡腾,變?yōu)?23456.87吻谋。
PS:每個人在具體的業(yè)務中可能要求不同,主要是按實際業(yè)務來欧引,我這邊是當粘貼的數(shù)字太大的時候怀各,截取了還能放下的位數(shù)倔韭,你也可以干脆發(fā)現(xiàn)粘貼的數(shù)加進去后超標了。直接返回空字符串瓢对。
附上最終的代碼:
PointInputFilter.java:
public class PointInputFilter implements InputFilter {
private static final int DECIMAL_DIGITS = 2;//小數(shù)的位數(shù)
private static final int INTEGER_DIGITS = 6;//整數(shù)位的位數(shù)
private static final int TOTAL_DIGITS = 9; //整數(shù)部分 + “小數(shù)點” + 小數(shù)部分
private int currentLimitDigits = INTEGER_DIGITS;
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// 刪除等特殊字符寿酌,直接返回
if ("".equals(source.toString())) {
return null;
}
/*
如果想要直接禁止復制粘貼多個數(shù)字,直接這邊限制硕蛹。
if(source.length() > 1){
return "";
}*/
String dValue = dest.toString();
String[] splitArray = dValue.split("\\.");
switch (splitArray.length) {
case 1:
if (dValue.indexOf(".") != -1) {
currentLimitDigits = TOTAL_DIGITS;
} else {
currentLimitDigits = INTEGER_DIGITS;
}
if (source.length() > 1) {
String sValue = source.toString();
String[] subSplitArray = sValue.split("\\.");
switch (subSplitArray.length) {
case 1:
if (source.length() + dest.length() > currentLimitDigits) {
return source.subSequence(0, currentLimitDigits - dest.length());
}
break;
case 2:
String content = "";
if (dstart == dest.length()) {
if (subSplitArray[0].length() + dest.length() > INTEGER_DIGITS) {
content += subSplitArray[0].subSequence(0, INTEGER_DIGITS - dest.length());
} else {
content += subSplitArray[0];
}
if (subSplitArray[1].length() > DECIMAL_DIGITS) {
content += "."+ subSplitArray[1].substring(0, DECIMAL_DIGITS);
} else {
content += "."+ subSplitArray[1];
}
return content;
} else {
if (subSplitArray[0].length() + dest.length() > INTEGER_DIGITS) {
content += subSplitArray[0].subSequence(0, INTEGER_DIGITS - dest.length());
} else {
content += subSplitArray[0];
}
}
return content;
default:
break;
}
}
if (splitArray[0].length() >= currentLimitDigits && !".".equals(source.toString())) {
return "";
}
break;
case 2:
String integerValue = splitArray[0];
String dotValue = splitArray[1];
int dotIndex = dValue.indexOf(".");
if (dstart <= dotIndex) {
if (integerValue.length() >= INTEGER_DIGITS) {
return "";
} else if (source.length() + integerValue.length() >= INTEGER_DIGITS) {
return source.subSequence(0, INTEGER_DIGITS - integerValue.length());
}
} else {
if (dotValue.length() >= DECIMAL_DIGITS) {
return "";
} else if (source.length() + dotValue.length() >= DECIMAL_DIGITS) {
return source.subSequence(0, DECIMAL_DIGITS - dotValue.length());
}
}
break;
default:
break;
}
return null;
}
}
總結:
完畢醇疼。終于可以安心下班了。哈哈妓美。。鲤孵。