高仿支付宝密码输入框

作者: 程序亦非猿580230 | 来源:发表于2018-11-01 14:57 被阅读30次

    先上图

    device-2018-11-01-142638.gif

    自定义键盘view

    public class PwdKeyboardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener {
        private static final int KEY_EMPTY = -10;
        private int delKeyBackgroundColor = 0xffcccccc;
        private Rect keyIconRect;
    
        public PwdKeyboardView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
    
        public PwdKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        private void init(Context context) {
            Keyboard keyboard = new Keyboard(context, R.xml.key_password_number);
            setKeyboard(keyboard);
            setEnabled(true);
            setFocusable(true);
            setPreviewEnabled(false);  // 设置点击按键不显示预览气泡
            setOnKeyboardActionListener(this);
        }
    
        @Override
        public void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            List<Keyboard.Key> keys = getKeyboard().getKeys();
            for (Keyboard.Key key : keys) {
                if (key.codes[0] == KEY_EMPTY) {
                    drawKeyBackground(key, canvas, getResources().getColor(R.color.colorKeyPress));
                }
                if (key.codes[0] == Keyboard.KEYCODE_DELETE) {
                    drawKeyBackground(key, canvas, getResources().getColor(R.color.colorKeyPress));
                    drawKeyIcon(key, canvas, getResources().getDrawable(R.mipmap.ic_delete));
                }
            }
        }
    
        /**
         * 绘制按键的背景
         *
         * @param key
         * @param canvas
         * @param color
         */
        private void drawKeyBackground(Keyboard.Key key, Canvas canvas, int color) {
            ColorDrawable colorDrawable = new ColorDrawable(color);
            colorDrawable.setBounds(key.x, key.y, key.x + key.width, key.y + key.height);
            colorDrawable.draw(canvas);
        }
    
        /**
         * 绘制按键的 icon
         *
         * @param key
         * @param canvas
         * @param iconDrawable
         */
    
        private void drawKeyIcon(Keyboard.Key key, Canvas canvas, Drawable iconDrawable) {
    
            if (iconDrawable == null) {
                return;
            }
    
            if (keyIconRect == null || keyIconRect.isEmpty()) {
                // 得到 keyicon 的显示大小,因为图片放在不同的drawable-dpi目录下,显示大小也不一样
                int intrinsicWidth = iconDrawable.getIntrinsicWidth();
                int intrinsicHeight = iconDrawable.getIntrinsicHeight();
                int drawWidth = intrinsicWidth;
                int drawHeight = intrinsicHeight;
                // 限制图片的大小,防止图片按键范围
                if (drawWidth > key.width) {
                    drawWidth = key.width;
                    // 此时高就按照比例缩放
                    drawHeight = (int) (drawWidth * 1.0f / intrinsicWidth * intrinsicHeight);
                } else if (drawHeight > key.height) {
                    drawHeight = key.height;
                    drawWidth = (int) (drawHeight * 1.0f / intrinsicHeight * intrinsicWidth);
                }
                // 获取图片的 x,y 坐标,图片在按键的正中间
                int left = key.x + key.width / 2 - drawWidth / 2;
                int top = key.y + key.height / 2 - drawHeight / 2;
                keyIconRect = new Rect(left, top, left + drawWidth, top + drawHeight);
            }
    
            if (keyIconRect != null && !keyIconRect.isEmpty()) {
                iconDrawable.setBounds(keyIconRect);
                iconDrawable.draw(canvas);
            }
    
        }
    
    
        @Override
        public void onPress(int primaryCode) {
    
        }
    
        @Override
        public void onRelease(int primaryCode) {
    
        }
    
        @Override
        public void onKey(int primaryCode, int[] keyCodes) {
    //        Log.d(TAG, "onKey: primaryCode = " + primaryCode + ", keyCodes = " + Arrays.toString(keyCodes));
            if (primaryCode == KEY_EMPTY) {
                return;
            }
            if (listener != null) {
                if (primaryCode == Keyboard.KEYCODE_DELETE) {
                    listener.onDelete();
                } else {
                    listener.onInput(String.valueOf((char) primaryCode));
                }
            }
    
    
        }
    
        @Override
        public void onText(CharSequence charSequence) {
    
        }
    
        @Override
        public void swipeLeft() {
    
        }
    
        @Override
        public void swipeRight() {
    
        }
    
        @Override
        public void swipeDown() {
    
        }
    
        @Override
        public void swipeUp() {
    
        }
    
        public interface OnKeyListener {
            void onInput(String text);
    
            void onDelete();
        }
    
        private OnKeyListener listener;
    
        public void setOnKeyListener(OnKeyListener listener) {
            this.listener = listener;
        }
    
    }
    
    

    自定义EditText输入框

    public class PwdEditText extends EditText {
    
        private final int STYLE_RECTANGLE = 0;
    
        private final int STYLE_ROUND_RECTANGLE = 1;
    
        private final int DEFAULT_STYLE = STYLE_RECTANGLE;
    
        private final int DEFAULT_PWD_COUNT = 6;
    
        private final float DEFAULT_STROKE_RADIUS = dp2Px(3);
    
        private final float DEFAULT_STROKE_WIDTH = dp2Px(1);
    
        private final int DEFAULT_STROKE_COLOR = Color.parseColor("#90cccccc");
    
        private final int DEFAULT_DOT_COLOR = Color.BLACK;
    
        private final float DEFAULT_DOT_RADIUS = dp2Px(4);
    
        private int style;   // 控件的样式,矩形或圆角矩形
    
        private float strokeRadius;  // 边框圆角的半径
    
        private float strokeWidth;   // 边框宽度
    
        private int strokeColor;  // 边框颜色
    
        private int pwdDotColor;  // 密码圆点颜色
    
        private float pwdDotRadius;  // 密码圆点半径
    
        private int mWidth;  // 控件宽度
    
        private int mHeight;  // 控件高度
    
        private Paint strokePaint;    // 绘制边框paint
    
        private Paint pwdDotPaint;    // 绘制密码圆点paint
    
        private int mCount;   // 密码框个数
    
        private float cellWidth;   // 每个密码框的宽度
    
        private float halfStrokeWidth;
    
        private int mCurInputCount;  // 当前输入字符个数
    
    
        public PwdEditText(Context context) {
            this(context, null);
            Log.i("debug", "one params");
        }
    
        /**
         * 无论xml布局文件中有没有写自定义属性,都调用两个参数的构造函数
         */
        public PwdEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
            Log.i("debug", "two params");
            initAttrs(context, attrs);
            init();
        }
    
        /**
         * 当有自定义的样式时,调用三个参数的构造函数
         */
        public PwdEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            Log.i("debug", "three params");
        }
    
        /**
         * 初始化自定义属性
         */
        private void initAttrs(Context context, AttributeSet attrs) {
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PwdEditText);
            style = typedArray.getInt(R.styleable.PwdEditText_style, DEFAULT_STYLE);
            mCount = typedArray.getInt(R.styleable.PwdEditText_pwdCount, DEFAULT_PWD_COUNT);
            strokeColor = typedArray.getColor(R.styleable.PwdEditText_strokeColor, DEFAULT_STROKE_COLOR);
            strokeWidth = typedArray.getDimension(R.styleable.PwdEditText_strokeWidth, DEFAULT_STROKE_WIDTH);
            strokeRadius = typedArray.getDimension(R.styleable.PwdEditText_strokeRadius, DEFAULT_STROKE_RADIUS);
            pwdDotColor = typedArray.getColor(R.styleable.PwdEditText_dotColor, DEFAULT_DOT_COLOR);
            pwdDotRadius = typedArray.getDimension(R.styleable.PwdEditText_dotRadius, DEFAULT_DOT_RADIUS);
            typedArray.recycle();
        }
    
        /**
         * 初始化操作
         */
        private void init() {
            // 初始化边框画笔
            strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            strokePaint.setColor(strokeColor);
            strokePaint.setStrokeWidth(strokeWidth);
            strokePaint.setStyle(Paint.Style.STROKE);
    
            // 初始化圆点画笔
            pwdDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            pwdDotPaint.setStyle(Paint.Style.FILL);
            pwdDotPaint.setColor(pwdDotColor);
    
            halfStrokeWidth = strokeWidth / 2;
    
            // 设置光标不可见
            setCursorVisible(false);
            // 设置限定最大长度
            setFilters(new InputFilter[]{new InputFilter.LengthFilter(mCount)});
            // 设置无背景
    //        setBackgroundColor(getResources().getColor(android.R.color.transparent));
    
            setBackgroundColor(Color.WHITE);
    
            setMaxLines(1);
    
            setFocusable(false);
    
            this.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    if (onTextChangedListener != null) {
                        onTextChangedListener.beforeTextChanged(s, start, count, after);
                    }
                }
    
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (onTextChangedListener != null) {
                        onTextChangedListener.onTextChanged(s, start, before, count);
                    }
                    mCurInputCount = s.toString().length();
    
                    // 输入完成的回调
                    if (mCurInputCount == mCount) {
                        if (onTextInputListener != null) {
                            onTextInputListener.onComplete(s.toString());
                        }
                    }
                }
    
                @Override
                public void afterTextChanged(Editable s) {
                    if (onTextChangedListener != null) {
                        onTextChangedListener.afterTextChanged(s);
                    }
                }
            });
    
    
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            mWidth = w;
            mHeight = h;
            cellWidth = (mWidth - strokeWidth) / mCount;
    
        }
    
    
        @Override
        protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);   // 不需要父类的绘制方法
            drawStroke(canvas);
            drawVerticalDivder(canvas);
            drawPwdDot(canvas);
    
        }
    
        private void drawPwdDot(Canvas canvas) {
            for (int i = 1; i <= mCurInputCount; i++) {
                canvas.drawCircle(halfStrokeWidth + cellWidth / 2 + cellWidth * (i - 1), (mHeight) / 2,
                        pwdDotRadius, pwdDotPaint);
            }
    
        }
    
        // 绘制竖直方向分割线
        private void drawVerticalDivder(Canvas canvas) {
            if (mCount == 1) {
                return;
            }
            for (int i = 1; i < mCount; i++) {
                canvas.drawLine(halfStrokeWidth + cellWidth * i, halfStrokeWidth, halfStrokeWidth + cellWidth * i,
                        mHeight - halfStrokeWidth, strokePaint);
            }
        }
    
        private void drawStroke(Canvas canvas) {
            if (style == STYLE_RECTANGLE) {
                canvas.drawRect(halfStrokeWidth, halfStrokeWidth, mWidth - halfStrokeWidth,
                        mHeight - halfStrokeWidth, strokePaint);
            } else {
                RectF rectF = new RectF(halfStrokeWidth, halfStrokeWidth, mWidth - halfStrokeWidth,
                        mHeight - halfStrokeWidth);
                canvas.drawRoundRect(rectF, strokeRadius, strokeRadius, strokePaint);
            }
        }
    
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_ENTER) {
                return false;
            }
            return super.onKeyDown(keyCode, event);
        }
    
        private float dp2Px(int dpValue) {
            return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics());
        }
    
        public interface OnTextChangedListener {
            void beforeTextChanged(CharSequence s, int start, int count, int after);
    
            void onTextChanged(CharSequence s, int start, int before, int count);
    
            void afterTextChanged(Editable s);
        }
    
    
        public interface OnTextInputListener {
            void onComplete(String result);
        }
    
        private OnTextInputListener onTextInputListener;
    
        public void setOnTextInputListener(OnTextInputListener onTextInputListener) {
            this.onTextInputListener = onTextInputListener;
        }
    
    
        private OnTextChangedListener onTextChangedListener;
    
        public void addTextChangedListener(OnTextChangedListener listener) {
            this.onTextChangedListener = listener;
        }
    
    
    }
    
    

    fragment

    public class PayDialogFragment extends DialogFragment implements PwdEditText.OnTextInputListener {
    
        private static final String TAG = "PayDialogFragment";
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
        }
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable Bundle savedInstanceState) {
            Log.d(TAG, "onCreateView: ");
            //去掉dialog的标题,需要在setContentView()之前
            getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
            getDialog().setCanceledOnTouchOutside(false);
            View view = inflater.inflate(R.layout.layout_pay_dialog, null);
            ImageView exitImgView = view.findViewById(R.id.iv_exit);
            exitImgView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    PayDialogFragment.this.dismiss();
                }
            });
            final PwdEditText editText = view.findViewById(R.id.et_input);
            editText.setOnTextInputListener(this);
            PwdKeyboardView keyboardView = view.findViewById(R.id.key_board);
            keyboardView.setOnKeyListener(new PwdKeyboardView.OnKeyListener() {
                @Override
                public void onInput(String text) {
                    Log.d(TAG, "onInput: text = " + text);
                    editText.append(text);
                    String content = editText.getText().toString();
                    Log.d(TAG, "onInput: content = " + content);
                }
    
                @Override
                public void onDelete() {
                    Log.d(TAG, "onDelete: ");
                    String content = editText.getText().toString();
                    if (content.length() > 0) {
                        editText.setText(content.substring(0, content.length() - 1));
                    }
    
    
                }
            });
            return view;
        }
    
    
        @Override
        public void onStart() {
            super.onStart();
            Log.d(TAG, "onStart: ");
            Window window = getDialog().getWindow();
            WindowManager.LayoutParams lp = window.getAttributes();
            lp.windowAnimations = R.style.DialogFragmentAnimation;
            lp.width = WindowManager.LayoutParams.MATCH_PARENT;
            lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
            //设置dialog的位置在底部
            lp.gravity = Gravity.BOTTOM;
            window.setAttributes(lp);
            //去掉dialog默认的padding
    //        window.getDecorView().setPadding(0, 0, 0, 0);
    
            window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    
        }
    
        @Override
        public void onComplete(String result) {
            Log.d(TAG, "onComplete: result = " + result);
            Toast.makeText(getContext(), "input complete : " + result, Toast.LENGTH_SHORT).show();
        }
    }
    
    

    anim dialog_in.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="@android:integer/config_shortAnimTime"
            android:fromYDelta="100%p"
            android:toYDelta="0%p" />
    
        <alpha
            android:duration="@android:integer/config_shortAnimTime"
            android:fromAlpha="0.0"
            android:toAlpha="1.0" />
    
    
    
    </set>
    

    dialog_out.xml

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate
            android:duration="@android:integer/config_mediumAnimTime"
            android:fromYDelta="0%p"
            android:toYDelta="100%p" />
    
        <alpha
            android:duration="@android:integer/config_mediumAnimTime"
            android:fromAlpha="1.0"
            android:toAlpha="0.3" />
    
    
    </set>
    

    layout_pay_dialog.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white">
    
        <ImageView
            android:id="@+id/iv_exit"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:src="@drawable/ic_exit" />
    
    
        <com.wawi.android.pwdkeyboardView.PwdEditText
            android:id="@+id/et_input"
            android:layout_width="300dp"
            android:layout_height="52dp"
            android:layout_below="@id/iv_exit"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="30dp"
            app:pwdCount="6"
            app:style="roundRectangle" />
    
    
        <com.wawi.android.pwdkeyboardView.PwdKeyboardView
            android:id="@+id/key_board"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/et_input"
            android:layout_marginTop="40dp"
            android:paddingTop="0.5dp"
            android:background="#E2E7ED"
            android:keepScreenOn="true"
            android:keyBackground="@drawable/selector_key_board"
            android:keyTextColor="@android:color/black"
            android:keyTextSize="26sp"
            android:shadowRadius="0" />
    
    
    </RelativeLayout>
    
    

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="PwdEditText">
            <attr name="style" format="enum">
                <enum name="rectangle" value="0" />
                <enum name="roundRectangle" value="1" />
            </attr>
            <attr name="pwdCount" format="integer" />
            <attr name="strokeRadius" format="dimension" />
            <attr name="strokeWidth" format="dimension" />
            <attr name="strokeColor" format="color" />
            <attr name="dotColor" format="color" />
            <attr name="dotRadius" format="dimension" />
        </declare-styleable>
    
    
    </resources>
    
     <style name="DialogFragmentAnimation" parent="android:Animation">
            <item name="android:windowEnterAnimation">@anim/dialog_in</item>
            <item name="android:windowExitAnimation">@anim/dialog_out</item>
        </style>
    

    键盘xml

    <?xml version="1.0" encoding="utf-8"?>
    <Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
        android:horizontalGap="1dp"
        android:keyHeight="9%p"
        android:keyWidth="33.3333%p"
        android:verticalGap="1dp">
    
        <Row>
            <Key
                android:codes="49"
                android:keyLabel="1" />
    
            <Key
                android:codes="50"
                android:keyLabel="2" />
    
            <Key
                android:codes="51"
                android:keyLabel="3" />
        </Row>
    
        <Row>
            <Key
                android:codes="52"
                android:keyLabel="4" />
    
            <Key
                android:codes="53"
                android:keyLabel="5" />
    
            <Key
                android:codes="54"
                android:keyLabel="6" />
        </Row>
    
        <Row>
            <Key
                android:codes="55"
                android:keyLabel="7" />
    
            <Key
                android:codes="56"
                android:keyLabel="8" />
    
            <Key
                android:codes="57"
                android:keyLabel="9" />
        </Row>
    
    
        <Row>
            <Key
                android:codes="-10"
                android:keyLabel="" />
    
            <Key
                android:codes="48"
                android:keyLabel="0" />
    
            <Key
                android:codes="-5"
                android:keyLabel="" />
        </Row>
    
    
    </Keyboard>
    

    使用

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        public void pay(View view) {
            PayDialogFragment payDialogFragment = new PayDialogFragment();
            payDialogFragment.show(getSupportFragmentManager(), "payFragment");
        }
    }
    
    

    结束

    相关文章

      网友评论

        本文标题:高仿支付宝密码输入框

        本文链接:https://www.haomeiwen.com/subject/jihxxqtx.html