項目需求討論--可能是用InputFilter來做的最好的金額限制

看慣了可能是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.處理通過粘貼復制的方式輸入

這里我們可以有二種處理方式:

  1. 直接就干脆不讓多位數(shù)字粘貼進來涣仿。
  2. 針對多位數(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;
    }
}

總結:

完畢醇疼。終于可以安心下班了。哈哈妓美。。鲤孵。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壶栋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子普监,更是在濱河造成了極大的恐慌贵试,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凯正,死亡現(xiàn)場離奇詭異毙玻,居然都是意外死亡,警方通過查閱死者的電腦和手機廊散,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門桑滩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人允睹,你說我怎么就攤上這事运准』系” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵胁澳,是天一觀的道長该互。 經(jīng)常有香客問我,道長韭畸,這世上最難降的妖魔是什么宇智? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮胰丁,結果婚禮上随橘,老公的妹妹穿的比我還像新娘。我一直安慰自己隘马,他們只是感情好太防,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酸员,像睡著了一般蜒车。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幔嗦,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天酿愧,我揣著相機與錄音,去河邊找鬼邀泉。 笑死嬉挡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的汇恤。 我是一名探鬼主播庞钢,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼因谎!你這毒婦竟也來了基括?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤财岔,失蹤者是張志新(化名)和其女友劉穎风皿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匠璧,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡桐款,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了夷恍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魔眨。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冰沙,到底是詐尸還是另有隱情侨艾,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布拓挥,位于F島的核電站唠梨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏侥啤。R本人自食惡果不足惜当叭,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望盖灸。 院中可真熱鬧蚁鳖,春花似錦、人聲如沸赁炎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽徙垫。三九已至讥裤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間姻报,已是汗流浹背己英。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吴旋,地道東北人损肛。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像荣瑟,于是被迫代替她去往敵國和親治拿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容