仿支付寶密碼輸入彈窗

仿支付寶密碼輸入彈窗

效果圖

源碼

可設置自定義鍵盤佈局;
可攔截並自定義按鍵響應(固定功能按鍵不可更改);
可設置按鍵位置隨機(僅隨機字母和數字)
密碼輸入框可設置顯示與不顯示密碼

/**
 * 創建者:TomCat0916
 * 創建時間:2020/4/25
 * 功能描述:
 * 1、重載樣式{@link R.style#PassWordEditText}和{@link R.style#RandomKeyboardDialog}可自定義佈局中密碼框和軟鍵盤樣式
 * 2、設置{@link #xml}自定義軟鍵盤佈局,通過{@link Builder#setCustomKeyDealListener(OnCustomKeyDealListener)}監聽配置自定義鍵盤操作(出固定功能鍵shift/delete/enter)
 * 3、不改變固有控件id情況下重載{@link R.layout#dialog_keyboard},可實現佈局自定義
 * 示例
 * <p>
 * RandomKeyboardDialog.builder()
 *                     .isUseStateView(true)
 *                     .setOnInputCompletedListener((value, callback) -> {
 *                          new Handler().postDelayed(() -> callback.onCheckedResult(true), 3000);
 *                     })
 *                     .create(context)
 *                     .show();
 * </p>
 */
public class RandomKeyboardDialog extends BaseDialog implements View.OnClickListener, OnInputCompletedListener, OnCheckResultCallback {

    private StateView stateView;
    private PasswordEditText etInput;
    private RandomKeyboard randomKeyboard;

    private OnInputCompletedListener listener;
    private OnCustomKeyDealListener keyDealListener;

    private @XmlRes
    int xml = 0;
    private String title;
    private int passwordLength;
    private boolean isVisible;
    private boolean isUseStateView;

    @Override
    public void destroy() {
        if (randomKeyboard!=null){
            randomKeyboard.onDestroy();
            randomKeyboard = null;
        }
        etInput = null;
        listener = null;
        stateView = null;
        keyDealListener = null;
        super.destroy();
    }

    private RandomKeyboardDialog(@NonNull Context context, Builder builder) {
        super(context, builder);
        isUseStateView = builder.isUseStateView;
        title = builder.title;
        if (builder.listener != null) {
            listener = builder.listener;
        }
        keyDealListener = builder.keyDealListener;
        xml = builder.xml;
        passwordLength = builder.passwordLength;
        isVisible = builder.isVisible;
    }

    @Override
    public void initView(View inflate) {
        //禁用系統輸入法
        if (getWindow() != null) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }
        ImageView imgDismiss = findViewById(R.id.img_dismiss);
        randomKeyboard = findViewById(R.id.random_keyboard);
        TextView tvTitle = findViewById(R.id.tv_title);
        if (tvTitle != null) {
            tvTitle.setText(title);
        }
        etInput = findViewById(R.id.et_input);
        stateView = findViewById(R.id.state_view);
        if (randomKeyboard != null && etInput != null) {
            etInput.setOnClickListener(this);
            etInput.requestFocus();
            etInput.setOnInputCompletedListener(this);
            etInput.setSelection(etInput.length());
            if (passwordLength > 0) {
                etInput.setPasswordLength(passwordLength);
            }
            etInput.setPasswordVisible(isVisible);
            try {
                context.getResources().getXml(xml);
                randomKeyboard.setCustomKeyboard(xml);
            } catch (Resources.NotFoundException e) {
                e.printStackTrace();
            }
            randomKeyboard.setOnCustomKeyDealListener(keyDealListener);
            randomKeyboard.bindEditText(etInput);
            randomKeyboard.isRandom(true);
            randomKeyboard.show();
        }
        if (imgDismiss != null) {
            imgDismiss.setOnClickListener(this);
        }
    }

    @Override
    public void initData() {

    }

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder extends BaseDialog.Builder {
        private String title;
        private OnInputCompletedListener listener;
        private boolean isUseStateView = false;
        private @XmlRes
        int xml = 0;
        private OnCustomKeyDealListener keyDealListener;
        private int passwordLength;
        private boolean isVisible = true;


        @Override
        public void destroy() {
            listener = null;
            keyDealListener = null;
        }

        public Builder setTitle(String title) {
            this.title = title;
            return this;
        }

        public Builder setOnInputCompletedListener(OnInputCompletedListener listener) {
            this.listener = listener;
            return this;
        }

        public Builder isUseStateView(boolean isUseStateView) {
            this.isUseStateView = isUseStateView;
            return this;
        }

        public Builder setKeyboardLayout(@XmlRes int xml) {
            this.xml = xml;
            return this;
        }

        public Builder setCustomKeyDealListener(OnCustomKeyDealListener keyDealListener) {
            this.keyDealListener = keyDealListener;
            return this;
        }

        public Builder setPasswordLength(int passwordLength) {
            this.passwordLength = passwordLength;
            return this;
        }

        public Builder setPasswordVisible(boolean isVisible) {
            this.isVisible = isVisible;
            return this;
        }

        public RandomKeyboardDialog create(Context context) {
            setGravity(Gravity.BOTTOM);
            setHeight(WindowManager.LayoutParams.MATCH_PARENT);
            setWith(WindowManager.LayoutParams.MATCH_PARENT);
            setLayoutResId(R.layout.dialog_keyboard);
            return new RandomKeyboardDialog(context, this);
        }

    }

    public void setOnInputCompletedListener(OnInputCompletedListener listener) {
        this.listener = listener;
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.et_input) {
            etInput.requestFocus();
            etInput.setSelection(etInput.length());
            randomKeyboard.show();
        } else if (id == R.id.img_dismiss) {
            dismiss();
        }
    }

    @Override
    public void onComplete(String value, OnCheckResultCallback callback) {
        if (listener != null) {
            if (isUseStateView && stateView != null) {
                stateView.show(StateView.STATE_LOADING);
            }
            listener.onComplete(value, this);
        }
    }

    @Override
    public void onCheckedResult(boolean isDeal) {
        if (isUseStateView && stateView != null) {
            stateView.hide();
        }
        if (isDeal) {
            dismiss();
        }
    }
}

其他

  • dialog_keyboard.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#33000000">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                android:background="@color/white"
                android:orientation="vertical">

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <ImageView
                        android:id="@+id/img_dismiss"
                        android:layout_width="55dp"
                        android:layout_height="55dp"
                        android:paddingTop="10dp"
                        android:paddingBottom="5dp"
                        android:paddingLeft="15dp"
                        android:src="@android:drawable/ic_delete" />

                    <TextView
                        android:id="@+id/tv_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:textColor="@color/black"
                        android:textSize="20sp"
                        android:textStyle="bold" />
                </FrameLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:background="@color/colorDivider" />

                <com.quanyou.libraryview.widget.PasswordEditText
                    android:id="@+id/et_input"
                    style="@style/PassWordEditText"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:background="@color/colorDivider" />
            </LinearLayout>

        </FrameLayout>

        <com.quanyou.libraryview.widget.RandomKeyboard
            android:id="@+id/random_keyboard"
            style="@style/RandomKeyboardDialog"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom" />
    </LinearLayout>

    <com.quanyou.baselibrary.widget.StateView
        android:id="@+id/state_view"
        android:layout_width="match_parent"
        android:visibility="gone"
        android:layout_height="match_parent" />

</FrameLayout>
  • styles.xml
 <style name="RandomKeyboardDialog" parent="RandomKeyboardParent">
        <item name="android:background">@color/white</item>
        <item name="android:keyBackground">@drawable/bg_keyboard_dialog</item>
        <item name="android:keyTextColor">@color/black</item>
        <item name="android:keyboardLayout">@xml/number_keyboard_dialog_layout</item>
        <item name="android:paddingBottom">10dp</item>
    </style>

    <style name="PassWordEditText">
        <item name="android:maxLength">6</item>
        <item name="android:background">@android:color/transparent</item>
        <item name="borderRadius">5dp</item>
        <item name="borderWidth">1dp</item>
        <item name="borderSpace">5dp</item>
        <item name="android:padding">15dp</item>
        <item name="android:layout_marginTop">20dp</item>
        <item name="android:layout_marginBottom">20dp</item>
        <item name="android:layout_marginLeft">30dp</item>
        <item name="android:layout_marginRight">30dp</item>
    </style>
  • number_keyboard_dialog_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0.25%p"
    android:keyWidth="33%p"
    android:keyHeight="50dp">
    <Row>
        <Key android:keyLabel="1" />
        <Key android:keyLabel="2" />
        <Key android:keyLabel="3" />
    </Row>
    <Row>
        <Key android:keyLabel="4" />
        <Key android:keyLabel="5" />
        <Key android:keyLabel="6" />
    </Row>
    <Row>
        <Key android:keyLabel="7" />
        <Key android:keyLabel="8" />
        <Key android:keyLabel="9" />
    </Row>
    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="48"
            android:horizontalGap="33.25%p"
            android:keyLabel="0" />
        <Key
            android:codes="-5"
            android:isModifier="true"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyLabel="delete" />
    </Row>
</Keyboard>

相關鏈接

BaseDialog :https://blog.csdn.net/TomCat0916/article/details/105769678

RandomKeyboard:https://blog.csdn.net/TomCat0916/article/details/105751838

PasswordEditText :https://blog.csdn.net/TomCat0916/article/details/105759569

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章