1. 程式人生 > >防止密碼輸入錯誤, 密碼明文顯示功能

防止密碼輸入錯誤, 密碼明文顯示功能

歡迎Follow我的GitHub, 關注我的CSDN.

Password

Book

在使用App的時候, 首次都需要輸入密碼. 有些人為了安全性, 密碼較長, 偶爾會輸入錯誤; 有些人忘記了密碼, 需要多次嘗試, 但又不知道是輸入錯誤, 還是密碼錯誤, 這些都會影響使用者體驗.

這一點, 移動端設計師們早有準備, 因為手機的私密性較強, 在輸入密碼時, 可以提示使用者顯式輸入, 增強準確性, 提升體驗. 這些當然是有成本的, 需要額外編寫功能. 因此, 我來講一下, 如何編寫密碼明文顯示的功能, 減少大家的學習成本.

本文原始碼的GitHub下載地址

要點
(1) 重寫EditText, 新增提示密碼顯示和隱藏的圖片.
(2) 判斷點選位置, 切換EditText的密碼顯示狀態.
(3) 在螢幕旋轉或配置改變時, 保留圖片的狀態資訊.

實現只有一個類和兩個圖片資源, 大家可以自由定製.

1. 佈局樣式

兩種密碼的顯示樣式, 一種是常規顯示, 一種是TextInputLayout顯示.

    <LinearLayout
        android:id="@+id/main_ll_container_1"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:gravity="center">

        <TextView
            android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="密碼:" android:textSize="20sp"/> <me.chunyu.spike.wcl_password_input_demo.PasswordEditText android:id="@+id/main_pet_password" android:layout_width="match_parent" android:layout_height="wrap_content"
android:gravity="center" android:hint="請輸入密碼"/> </LinearLayout> <android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/main_ll_container_1"> <me.chunyu.spike.wcl_password_input_demo.PasswordEditText android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:hint="請輸入密碼"/> </android.support.design.widget.TextInputLayout>

效果

效果

2. 提示圖示

初始化資源和佈局, 獲取密碼圖片的資源, 監聽EditText, 有文字時顯示圖示, 沒有文字時隱藏圖示.

    // 初始化佈局
    public void initFields(AttributeSet attrs, int defStyleAttr) {
        if (attrs != null) {
            // 獲取屬性資訊
            TypedArray styles = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordEditText, defStyleAttr, 0);
            try {
                // 根據引數, 設定Icon
                mShowPwdIcon = styles.getResourceId(R.styleable.PasswordEditText_pet_iconShow, mShowPwdIcon);
                mHidePwdIcon = styles.getResourceId(R.styleable.PasswordEditText_pet_iconHide, mHidePwdIcon);
            } finally {
                styles.recycle();
            }
        }

        // 密碼狀態
        setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);

        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s.length() > 0) {
                    // 有文字時顯示指示器
                    showPasswordVisibilityIndicator(true);
                } else {
                    mIsShowPwdIcon = false;
                    restorePasswordIconVisibility(mIsShowPwdIcon);
                    showPasswordVisibilityIndicator(false); // 隱藏指示器
                }
            }

            @Override public void afterTextChanged(Editable s) {

            }
        });
    }

setInputType設定密碼狀態, TYPE_TEXT_VARIATION_PASSWORD密文狀態.
通過pet_iconShow屬性, 可以選擇自定義密碼提示圖片.

3. 監聽事件

點選圖片, 切換顯示或隱藏密碼, 獲取點選位置, 和圖片位置進行比較, 判斷事件.

    @Override public boolean onTouchEvent(MotionEvent event) {
        if (mDrawableSide == null) {
            return super.onTouchEvent(event);
        }
        final Rect bounds = mDrawableSide.getBounds();
        final int x = (int) event.getRawX(); // 點選的位置

        int iconX = (int) getTopRightCorner().x;

        // Icon的位置
        int leftIcon = iconX - bounds.width();

        Log.e(TAG, "x: " + x + ", leftIcon: " + leftIcon);

        // 大於Icon的位置, 才能觸發點選
        if (x >= leftIcon) {
            togglePasswordIconVisibility(); // 變換狀態
            event.setAction(MotionEvent.ACTION_CANCEL);
            return false;
        }
        return super.onTouchEvent(event);
    }

切換明文或密文的密碼

    // 設定密碼指示器的狀態
    private void restorePasswordIconVisibility(boolean isShowPwd) {
        if (isShowPwd) {
            // 可視密碼輸入
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
        } else {
            // 非可視密碼狀態
            setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
        }

        // 移動游標
        setSelection(getText().length());
    }

4. 儲存狀態

重寫SavedState, 在旋轉螢幕時, 儲存和恢復顯示圖片資訊.

    // 儲存密碼狀態, 顯示Icon的位置
    protected static class PwdSavedState extends BaseSavedState {

        private final boolean mShowingIcon;

        private PwdSavedState(Parcelable superState, boolean showingIcon) {
            super(superState);
            mShowingIcon = showingIcon;
        }

        private PwdSavedState(Parcel in) {
            super(in);
            mShowingIcon = in.readByte() != 0;
        }

        public boolean isShowingIcon() {
            return mShowingIcon;
        }

        @Override
        public void writeToParcel(Parcel destination, int flags) {
            super.writeToParcel(destination, flags);
            destination.writeByte((byte) (mShowingIcon ? 1 : 0));
        }

        public static final Parcelable.Creator<PwdSavedState> CREATOR = new Creator<PwdSavedState>() {
            public PwdSavedState createFromParcel(Parcel in) {
                return new PwdSavedState(in);
            }

            public PwdSavedState[] newArray(int size) {
                return new PwdSavedState[size];
            }
        };
    }

動畫效果

動畫

現在可以把類複製到應用中, 更換圖片資源, 替換顯示密碼框, 給使用者更好的移動端體驗. 永遠追求極致, 追求不凡.

OK, that’s all! Enjoy it!