Android 自定義 EditText 達到從右邊輸入的效果

背景

最近項目要求可以輸入體重,而且小數點是自動輸入的,不需要用戶輸入。

這樣就帶來一個問題,體重的整數位可以是兩位,比如 60.5,也可以是三位,比如 100.5,如果單位是 g,也可以是四位,比如 1000.5。

那么小數點自動輸入的話,是在第二位整數后面輸入?還是在第三第四位整數后面輸入?

這個根本沒有辦法判斷!

所以 UX 提出了一個方案:小數點固定為兩位,輸入時從右邊開始輸入。

舉個例子:如果想輸入 60.55 的體重的時候
輸入6 → 0.06
輸入0 → 0.60
輸入5 → 6.05
輸入5 → 60.55

這樣的話我要輸入 66,豈不是要輸入 6600 ?這樣 Usability 真的好么?

后來在中石化圈存加油卡的時候,發現金額的輸入規則也是從右邊開始輸入的,我要圈存 500 元,輸入了 50000。看來是我孤陋寡聞了(=?Д?=)

自定義 EditText

為了達到從右邊開始輸入的效果,我們來自定義 EditText。
直接上代碼吧(講解請看代碼中的注釋)

/**
 * 從右邊開始輸入的 EditText
 */
public class InputFromEndDecimalEditText extends AppCompatEditText {

    // 整數位位數
    private int integerLength;
    // 小數位位數
    private int decimalLength;

    public InputFromEndDecimalEditText(Context context) {
        super(context);
        init(context, null);
    }

    public InputFromEndDecimalEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public InputFromEndDecimalEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.InputFromEndDecimalEditText);
        integerLength = a.getInteger(R.styleable.InputFromEndDecimalEditText_integerLength, 0);
        decimalLength = a.getInteger(R.styleable.InputFromEndDecimalEditText_decimalLength, 0);
        a.recycle();

        // 限制 EditText 的輸入長度
        setFilters(new InputFilter[]{new InputFilter.LengthFilter(integerLength + decimalLength + 1)});
        // 光標不可見(因為要控制光標始終在最后,所以不讓用戶看見光標)
        setCursorVisible(false);
        setTextChangeListener();
    }

    private void setTextChangeListener() {
        addTextChangedListener(new SimpleTextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // 利用正則表達式來判斷數字的格式是否達到要求
                if (!TextUtils.isEmpty(s) &&
                        !s.toString().matches("^(\\d{1," + integerLength + "}.\\d{" + decimalLength + "})$")) {
                    // 去掉非數字,也就是小數點
                    Integer userInputWithoutDecimalPoint = Integer.valueOf(s.toString().replaceAll("[^\\d]", ""));

                    if (count == 0 && userInputWithoutDecimalPoint == 0) {
                        // 刪除之后為 0 的話,全部刪除
                        setText(null);
                    } else {
                        StringBuilder userInputBuilder = new StringBuilder(userInputWithoutDecimalPoint.toString());

                        // 補 0
                        while (userInputBuilder.length() <= decimalLength) {
                            userInputBuilder.insert(0, '0');
                        }
                        // 插入小數點
                        userInputBuilder.insert(userInputBuilder.length() - decimalLength, '.');

                        setText(userInputBuilder.toString());
                        moveCursorToEnd();
                    }
                }
            }
        });
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        if (getText() != null && (selStart != getText().length() || selEnd != getText().length())) {
            moveCursorToEnd();
            return;
        }
        super.onSelectionChanged(selStart, selEnd);
    }

    private void moveCursorToEnd() {
        setSelection(getText().length());
    }
}

XML 中的用法如下

   <com.teletian.inputfromenddecimaledittext.InputFromEndDecimalEditText
        android:id="@+id/edit_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@null"
        android:gravity="right"
        android:hint="000.00"
        android:inputType="numberDecimal"
        android:textColor="@android:color/holo_blue_dark"
        android:textColorHint="@android:color/darker_gray"
        app:decimalLength="2"
        app:integerLength="3" />

沒有輸入的時候顯示 hint,提示用戶有幾位整數,有幾位小數。
為了把 hint 和正常的數值區分開,我們設置了 textColor 和 textColorHint 為不同的顏色。

以上代碼還有個小小的問題:
如果數值是以 double 類型存在數據庫中的,那么 66.00 會變成 66.0。那么下次顯示到 EditText 的時候就會變成 6.60。

為了解決這個問題,我們讓傳入到 EditText 的值變換成指定的小數位。
只要復寫 EditText 的 setText 方法就行了

    @Override
    public void setText(CharSequence text, BufferType type) {

        DecimalFormat decimalFormat = new DecimalFormat();
        decimalFormat.setMinimumIntegerDigits(1);
        decimalFormat.setMaximumIntegerDigits(integerLength);
        decimalFormat.setMinimumFractionDigits(decimalLength);
        decimalFormat.setMaximumFractionDigits(decimalLength);

        super.setText(TextUtils.isEmpty(text) ?
                text : decimalFormat.format(Double.valueOf(text.toString())), type);
    }

源碼

https://github.com/teletian/Android/tree/master/InputFromEndDecimalEditText

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容