Android进阶Android ViewAndroid知识

Android:仿支付宝交易密码框

2016-11-17  本文已影响1207人  Kisson

App需要支付场景的时候,都会让用户输入密码交易框,如果用系统或者第三方键盘可能导致密码泄露。因此,比较多的App会自定义密码输入键盘来提供安全性。本文依照支付宝密码输入界面来设计,同时提供随机键盘功能。
项目地址:Github

看效果图

密码输入框效果图

模拟器上,会导致线条绘制模糊。真机运行效果更棒。

数字密码键盘安全级别

低:系统提供键盘或者第三方输入法键盘。
中:自定义键盘,但不随机键盘数字。
高:自定义键盘,且随机键盘数字。

数字密码键盘实现原理

键盘实现的原理大致有两种方法。
1.利用系统提供的KeyboardView来完成。
2.另外一种就是自定义View来完成键盘绘制。
本文采取的自定义View方式绘制键盘。
因为数字键盘是九宫格的排列,所以首先考虑使用GridLayout。
因为GridLayout并不提供均匀分布的功能,所以我们得重新填充Child View。
解决思路如下:
1.填充键盘Key。
2.绘制键盘之间的分割线。
3.完成键盘Key点击事件监听。
4.输出键盘密码的输入。

看键盘源码

public class PasswordKeyboard extends GridLayout implements View.OnClickListener, View.OnTouchListener {

    public static final String DEL = "删除";

    public static final String DONE = "OK";
    //因为UED是给的是iPhone设计稿,所以是按照等比的思想设置键盘Key的高度和宽度
    private static final int IPHONE = 779;
    //每个键盘Key的宽度,为屏幕宽度的三分之一
    private int keyWidth = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth() / 3;
    //每个键盘Key的高度
    private int keyHeight = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight() * 59 / IPHONE;

    private int screenWidth = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();

    private Paint mPaint;
    //List集合存储Key,方便每次输错都能再次随机数字键盘
    private final List<Button> keyButtons = new ArrayList<>();

    private WorkHandler mWorkHandler;

    private static final int DELETE = 1;
    //WorkHandler 用于处理长按"删除"Key时,执行重复删除操作。
    private static class WorkHandler extends Handler {

        private int index = 0;

        int diffTime = 100;

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case DELETE:
                    PasswordKeyboard numberKeyBoard = (PasswordKeyboard) msg.obj;
                    numberKeyBoard.handlerClick(DEL);
                    removeMessages(DELETE);
                    Message message = obtainMessage(DELETE);
                    message.obj = numberKeyBoard;
                    if (diffTime > 40) {
                        diffTime = diffTime - index;
                    }
                    sendMessageDelayed(message, diffTime);
                    index++;
                    break;
            }
        }

        public void reset() {
            index = 0;
            diffTime = 100;
        }
    }

    public PasswordKeyboard(Context context) {
        super(context);
        initView();
    }

    public PasswordKeyboard(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public PasswordKeyboard(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    @Override
    protected void onMeasure(int widthSpec, int heightSpec) {
        super.onMeasure(widthSpec, heightSpec);
        setMeasuredDimension(screenWidth, keyHeight * 4);
    }

    //重新设置键盘key位置
    public void resetKeyboard() {
        List<String> keyList = randomKeys(10);
        for (int i = 0; i < keyList.size(); i++) {
            keyButtons.get(i).setText(keyList.get(i));
            keyButtons.get(i).setTag(keyList.get(i));
        }
    }

    private void initView() {
        //必须设置调用该方法,不然onDraw方法不执行。如果ViewGroup没有背景,则其onDraw方法不执行
        setWillNotDraw(false);
        if (getChildCount() > 0) {
            keyButtons.clear();
            removeAllViews();
        }
        //获取随机键盘数字的字符串
        List<String> keyList = randomKeys(10);
        //填充键盘Key,用Button来完成Key功能
        for (int i = 0; i < keyList.size(); i++) {
            Button item = new Button(getContext());
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(keyWidth, keyHeight);
            item.setLayoutParams(params);
            item.setOnClickListener(this);
            item.setText(keyList.get(i));
            item.setBackgroundDrawable(getResources().getDrawable(R.drawable.key_selector));
            //监听"删除"的长按监听事件,完成重复删除操作
            if (DEL.equals(keyList.get(i))) {
                item.setOnTouchListener(this);
            }
            item.setTag(keyList.get(i));
            addView(item);
            keyButtons.add(item);
        }
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(Color.parseColor("#cccccc"));
            mPaint.setStrokeWidth(1);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制分割线
        canvas.drawLine(0, getMeasuredHeight() / 4, getMeasuredWidth(), getMeasuredHeight() / 4, mPaint);
        canvas.drawLine(0, 2 * getMeasuredHeight() / 4, getMeasuredWidth(), 2 * getMeasuredHeight() / 4, mPaint);
        canvas.drawLine(0, 3 * getMeasuredHeight() / 4, getMeasuredWidth(), 3 * getMeasuredHeight() / 4, mPaint);
        canvas.drawLine(getMeasuredWidth() / 3, 0, getMeasuredWidth() / 3, getMeasuredHeight(), mPaint);
        canvas.drawLine(2 * getMeasuredWidth() / 3, 0, 2 * getMeasuredWidth() / 3, getMeasuredHeight(), mPaint);
    }

    @Override
    public void onClick(View v) {
        String character = v.getTag().toString();
        handlerClick(character);
    }

    private void handlerClick(String character) {
        //密码字符输出回调
        if (mListener != null) {
            if (DONE.equals(character)) {
                mListener.onInput(DONE);
            } else if (DEL.equals(character)) {
                mListener.onInput(DEL);
            } else {
                mListener.onInput(character);
            }
        }
    }

    //生产键盘Key随机数字
    private List<String> randomKeys(int no) {
        int[] keys = new int[no];
        for (int i = 0; i < no; i++) {
            keys[i] = i;
        }
        Random random = new Random();
        for (int i = 0; i < no; i++) {
            int p = random.nextInt(no);
            int tmp = keys[i];
            keys[i] = keys[p];
            keys[p] = tmp;
        }
        List<String> keyList = new ArrayList<>();
        for (int key : keys) {
            keyList.add(String.valueOf(key));
        }
        //将空字符串插入到第10个位置,是个无操作的Key
        keyList.add(9, "");
        //将删除字符串插入最后
        keyList.add(DEL);
        return keyList;
    }

    public void setOnPasswordInputListener(OnPasswordInputListener listener) {
        this.mListener = listener;
    }

    private OnPasswordInputListener mListener;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        if (mWorkHandler == null) {
            mWorkHandler = new WorkHandler();
        }
        if (MotionEvent.ACTION_DOWN == event.getAction()) {
            Message msg = mWorkHandler.obtainMessage(DELETE);
            msg.obj = this;
            mWorkHandler.sendMessageDelayed(msg, 500);
        } else if (MotionEvent.ACTION_UP == event.getAction()) {
            mWorkHandler.removeMessages(DELETE);
            mWorkHandler.reset();
        } else if (MotionEvent.ACTION_CANCEL == event.getAction()) {
            mWorkHandler.removeMessages(DELETE);
            mWorkHandler.reset();
        } else if (MotionEvent.ACTION_MOVE == event.getAction()) {

        } else {
            //do nothing
        }
        return false;
    }

    public interface OnPasswordInputListener {
        void onInput(String number);
    }
}

密码显示框

因为不能明文显示输入,所以我们用“●”代替每位密码。自定义密码显示框比较简单,直接采取继承View方式完成。
解决思路如下。
1.支持密码位数设置。
2.绘制边框和分割线。
3.绘制“●”。
4.每次密码输入改变,重新绘制“●”。

看源码

public class PasswordView extends View {

    private int passwordCount;

    private int strokeColor;

    private Paint mCirclePaint;

    private Paint mPaint;

    private int symbolColor;

    private float mRadius;

    private float inputBoxStroke;

    private StringBuffer mText;

    public PasswordView(Context context) {
        super(context);
    }

    public PasswordView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.inputBox);
        //支持某些属性设置,比如密码位数,边框颜色、宽度,"●"的颜色、大小
        passwordCount = ta.getInteger(R.styleable.inputBox_passwordCount, 6);
        strokeColor = ta.getColor(R.styleable.inputBox_stokeColor, Color.GRAY);
        symbolColor = ta.getColor(R.styleable.inputBox_symbolColor, Color.BLACK);
        mRadius = ta.getDimension(R.styleable.inputBox_symbolRadius, 12);
        inputBoxStroke = ta.getDimension(R.styleable.inputBox_inputBoxStroke, 1f);
        //设置输入框圆角边框
        GradientDrawable gd = new GradientDrawable();
        gd.setColor(Color.WHITE);
        gd.setStroke((int) inputBoxStroke, strokeColor);
        gd.setCornerRadius(8);
        setBackgroundDrawable(gd);
        ta.recycle();
        if (mPaint == null) {
            mPaint = new Paint();
            mPaint.setColor(strokeColor);
            mPaint.setStrokeWidth(inputBoxStroke);
        }
        if (mCirclePaint == null) {
            mCirclePaint = new Paint();
            mCirclePaint.setColor(symbolColor);
            mCirclePaint.setStyle(Paint.Style.FILL);
        }
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int singleWidth = getMeasuredWidth() / passwordCount;
        int height = getMeasuredHeight();
        //绘制每个"●"之间的分割线
        for (int i = 1; i < passwordCount; i++) {
            canvas.drawLine(singleWidth * i, 0, singleWidth * i, height, mPaint);
        }
        if (mText != null) {
            //绘制"●"
            int textSize = mText.length() > passwordCount ? passwordCount : mText.length();
            for (int i = 1; i <= textSize; i++) {
                canvas.drawCircle(singleWidth * i - singleWidth / 2, height / 2, mRadius, mCirclePaint);
            }
        }
    }

    public int getPasswordCount() {
        return passwordCount;
    }
    //支持密码位数设置
    public void setPasswordCount(int passwordCount) {
        this.passwordCount = passwordCount;
    }
    //密码改变,重新绘制
    public void setPassword(CharSequence text) {
        mText = (StringBuffer) text;
        if (text.length() > passwordCount) {
            mText.delete(mText.length() - 1, mText.length());
            return;
        }
        postInvalidate();
    }

    public void clearPassword() {
        if (mText != null) {
            mText.delete(0, mText.length());
        }
    }

    public CharSequence getPassword() {
        return mText;
    }
}

进度条绘制

支付宝的验证密码过程的进度条是采取material design风格,不过做了特殊动画效果,当验证密码正确的时候,出现打“✔️”的动画。需解决问题如下。
1.material design进度条旋转的动画。
2.停止旋转动画,开始打“✔️”动画。
3.打“✔️”动画完成的回调。

看源码

进度条旋转动画过程,是参考网上一个例子,具体出处忘记了。若原作者看见,请见谅。

public class MDProgressBar extends View {

    private final static String TAG = MDProgressBar.class.getSimpleName();

    private static final float DEFAULT_MAX_ANGLE = -305f;

    private static final float DEFAULT_MIN_ANGLE = -19f;

    //默认的动画时间
    private static final int DEFAULT_DURATION = 660;

    private final static int DEFAULT_ARC_COLOR = Color.BLUE;
    //圆弧颜色
    private int arcColor = DEFAULT_ARC_COLOR;

    private AnimatorSet animatorSet;

    private float mBorderWidth;

    private Paint mPaint;

    private RectF arcRectF;

    private float startAngle = -45f;

    private float sweepAngle = -19f;

    private float incrementAngele = 0;
    //是否需要开始绘制对勾
    private boolean isNeedTick = false;

    private int mResize;

    private TickAnimation mTickAnimation;
    //判断"对勾"动画是否过半,"对勾"由两条线绘制而成。
    private boolean isAnimationOverHalf = false;
    //圆形进度条的半径
    private float mRadius;

    private float startY1;

    private float startX1;

    private float stopX1;

    private float stopY1;

    private float stopX2;

    private float stopY2;

    private OnPasswordCorrectlyListener mListener;

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

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

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.materialStatusProgressAttr);
        arcColor = typedArray.getColor(R.styleable.materialStatusProgressAttr_arcColor, Color.parseColor("#4a90e2"));
        mBorderWidth = typedArray.getDimension(R.styleable.materialStatusProgressAttr_progressBarBorderWidth,
                getResources().getDimension(R.dimen.material_status_progress_border));
        typedArray.recycle();
        mPaint = new Paint();
        mPaint.setColor(arcColor);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
        arcRectF = new RectF();
        mTickAnimation = new TickAnimation();
        mTickAnimation.setDuration(800);
        //对勾动画监听
        mTickAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //当对勾动画完成后,延迟一秒回掉,不然动画效果不明显
                if (mListener != null) {
                    postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mListener.onPasswordCorrectly();

                        }
                    }, 1000);
                }
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

    private void arcPaint() {
        mPaint.reset();
        mPaint.setColor(arcColor);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE);
    }

    private void linePaint() {
        mPaint.reset();
        mPaint.setColor(arcColor);
        mPaint.setStrokeWidth(mBorderWidth);
        mPaint.setAntiAlias(true);
    }
    //对勾动画完成回调
    public void setOnPasswordCorrectlyListener(OnPasswordCorrectlyListener listener) {
        this.mListener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        startY1 = getMeasuredHeight() / 2;
        mRadius = getMeasuredHeight() / 2 - 2 * mBorderWidth;
        startX1 = startY1 - getMeasuredHeight() / 5;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        arcPaint();
        canvas.drawArc(arcRectF, startAngle + incrementAngele, sweepAngle, false, mPaint);
        if (animatorSet == null || !animatorSet.isRunning() && !isNeedTick) {
            startAnimation();
        }
        if (isNeedTick) {
            //补全圆
            arcPaint();
            canvas.drawArc(arcRectF, startAngle + incrementAngele + sweepAngle, 360 - sweepAngle, false, mPaint);
            linePaint();
            //画第一根线
            canvas.drawLine(startX1, startY1, stopX1, stopY1, mPaint);
            if (isAnimationOverHalf) {
                //-2 +2 是为了两根线尽可能靠拢
                canvas.drawLine(stopX1 - 2, stopY1 + 2, stopX2, stopY2, mPaint);
            }
        }
    }
    //对勾动画
    private class TickAnimation extends Animation {

        @Override
        protected void applyTransformation(final float interpolatedTime, Transformation t) {
            super.applyTransformation(interpolatedTime, t);
            if (interpolatedTime <= 0.5f) {
                stopX1 = startX1 + mRadius / 3 * interpolatedTime * 2;
                stopY1 = startY1 + mRadius / 3 * interpolatedTime * 2;
                isAnimationOverHalf = false;
            } else {
                stopX2 = stopX1 + (mRadius - 20) * (interpolatedTime - 0.5f) * 2;
                stopY2 = stopY1 - (mRadius - 20) * (interpolatedTime - 0.5f) * 2;
                isAnimationOverHalf = true;
            }
            invalidate();
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mResize = (w < h) ? w : h;
        setBound();
    }

    private void setBound() {
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        arcRectF.set(paddingLeft + mBorderWidth, paddingTop + mBorderWidth, mResize - paddingLeft - mBorderWidth, mResize - paddingTop - mBorderWidth);
    }

    public void startAnimation() {
        isNeedTick = false;
        if (animatorSet != null && animatorSet.isRunning()) {
            animatorSet.cancel();
        }
        if (animatorSet == null) {
            animatorSet = new AnimatorSet();
        }
        AnimatorSet set = loopAnimator();
        animatorSet.play(set);
        animatorSet.addListener(new AnimatorListener() {

            private boolean isCancel = false;

            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!isCancel) {
                    startAnimation();
                }
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                isCancel = true;
            }
        });
        animatorSet.start();
    }

    /**
     * 进度条旋转的动画
     */
    private AnimatorSet loopAnimator() {
        //从小圈到大圈
        ValueAnimator holdAnimator1 = ValueAnimator.ofFloat(incrementAngele + DEFAULT_MIN_ANGLE, incrementAngele + 115f);
        holdAnimator1.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                incrementAngele = (float) animation.getAnimatedValue();
            }
        });
        holdAnimator1.setDuration(DEFAULT_DURATION);
        holdAnimator1.setInterpolator(new LinearInterpolator());
        ValueAnimator expandAnimator = ValueAnimator.ofFloat(DEFAULT_MIN_ANGLE, DEFAULT_MAX_ANGLE);
        expandAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sweepAngle = (float) animation.getAnimatedValue();
                incrementAngele -= sweepAngle;
                invalidate();
            }
        });
        expandAnimator.setDuration(DEFAULT_DURATION);
        expandAnimator.setInterpolator(new DecelerateInterpolator(2));
        //从大圈到小圈
        ValueAnimator holdAnimator = ValueAnimator.ofFloat(startAngle, startAngle + 115f);
        holdAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                startAngle = (float) animation.getAnimatedValue();
            }
        });

        holdAnimator.setDuration(DEFAULT_DURATION);
        holdAnimator.setInterpolator(new LinearInterpolator());
        ValueAnimator narrowAnimator = ValueAnimator.ofFloat(DEFAULT_MAX_ANGLE, DEFAULT_MIN_ANGLE);
        narrowAnimator.addUpdateListener(new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                sweepAngle = (float) animation.getAnimatedValue();
                invalidate();
            }
        });

        narrowAnimator.setDuration(DEFAULT_DURATION);
        narrowAnimator.setInterpolator(new DecelerateInterpolator(2));

        AnimatorSet set = new AnimatorSet();
        set.play(holdAnimator1).with(expandAnimator);
        set.play(holdAnimator).with(narrowAnimator).after(holdAnimator1);
        return set;
    }
    //清除动画
    private void cancelAnimator() {
        if (animatorSet != null) {
            animatorSet.cancel();
            isNeedTick = true;
        }
    }

    public void setSuccessfullyStatus() {
        if (animatorSet != null) {
            animatorSet.cancel();
            isNeedTick = true;
            startAnimation(mTickAnimation);
        }
    }

//重新setVisibility方法,当View不可见停止动画,及时释放资源。
    @Override
    public void setVisibility(int visibility) {
        switch (visibility) {
            case View.VISIBLE:
                startAnimation();
                break;
            case View.INVISIBLE:
                cancelAnimator();
                break;
            case View.GONE:
                cancelAnimator();
                break;
            default:
                break;
        }
        super.setVisibility(visibility);
    }

    public void setBorderWidth(int width) {
        this.mBorderWidth = width;
    }

    public void setArcColor(int color) {
        this.arcColor = color;
    }

    public interface OnPasswordCorrectlyListener {
        void onPasswordCorrectly();
    }

}

仿支付宝密码输入对话框

所有自定义控件完成,最后就是组装的过程。本文采用DialogFragment进行封装。同时,提供各个点击事件的回调。

public interface Callback {
   //忘记密码
    void onForgetPassword();
   //密码输入完成,比如密码长度为六位,当密码输入六位时候,直接 发出密码校验请求
    void onPasswordCompleted(CharSequence password);
    //密码输入正确
    void onPasswordCorrectly();
   //取消弹出框
    void onCancel();
}

看源码

public class PasswordKeypad extends DialogFragment implements View.OnClickListener, PasswordKeyboard.OnPasswordInputListener,
        MDProgressBar.OnPasswordCorrectlyListener {

    private TextView errorMsgTv;

    private Callback mCallback;

    private RelativeLayout passwordContainer;

    private MDProgressBar progressBar;

    private PasswordView passwordView;

    private int passwordCount;

    private boolean passwordState = true;

    PasswordKeyboard numberKeyBoard;

    private StringBuffer mPasswordBuffer = new StringBuffer();

    @Override
    public void onAttach(Activity context) {
        super.onAttach(context);
        if (context instanceof Callback) {
            mCallback = (Callback) context;
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.password_keypad, container, false);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NO_TITLE, 0);
    }

    @Override
    public void onStart() {
        super.onStart();
        DisplayMetrics dm = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
        Window window = getDialog().getWindow();
        //去掉边框
        window.setBackgroundDrawable(new ColorDrawable(0xffffffff));
        window.setLayout(dm.widthPixels, window.getAttributes().height);
        window.setWindowAnimations(R.style.exist_menu_animstyle);
        window.setGravity(Gravity.BOTTOM);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        errorMsgTv = (TextView) view.findViewById(R.id.error_msg);
        TextView forgetPasswordTv = (TextView) view.findViewById(R.id.forget_password);
        TextView cancelTv = (TextView) view.findViewById(R.id.cancel_dialog);

        passwordContainer = (RelativeLayout) view.findViewById(R.id.password_content);
        progressBar = (MDProgressBar) view.findViewById(R.id.password_progressBar);
        progressBar.setOnPasswordCorrectlyListener(this);
        passwordView = (PasswordView) view.findViewById(R.id.password_inputBox);
        //设置密码长度
        if (passwordCount > 0) {
            passwordView.setPasswordCount(passwordCount);
        }

        numberKeyBoard = (PasswordKeyboard) view.findViewById(R.id.password_keyboard);
        numberKeyBoard.setOnPasswordInputListener(this);

        cancelTv.setOnClickListener(this);
        forgetPasswordTv.setOnClickListener(this);
    }

    /**
     * 设置密码长度
     */
    public void setPasswordCount(int passwordCount) {
        this.passwordCount = passwordCount;
    }

    @Override
    public void onClick(View v) {
        if (R.id.cancel_dialog == v.getId()) {
            if (mCallback != null) {
                mCallback.onCancel();
            }
            dismiss();
        } else if (R.id.forget_password == v.getId()) {
            if (mCallback != null) {
                mCallback.onForgetPassword();
            }
        }
    }

    public void setCallback(Callback callBack) {
        this.mCallback = callBack;
    }

    public void setPasswordState(boolean correct) {
        setPasswordState(correct, "");
    }

    public void setPasswordState(boolean correct, String msg) {
        passwordState = correct;
        if (correct) {
            progressBar.setSuccessfullyStatus();
        } else {
            numberKeyBoard.resetKeyboard();
            passwordView.clearPassword();
            progressBar.setVisibility(View.GONE);
            passwordContainer.setVisibility(View.VISIBLE);
            errorMsgTv.setText(msg);
        }
    }

    @Override
    public void onPasswordCorrectly() {
        if (mCallback != null) {
            mCallback.onPasswordCorrectly();
        }
    }
    //开始进度条旋转
    private void startLoading(CharSequence password) {
        passwordContainer.setVisibility(View.INVISIBLE);
        progressBar.setVisibility(View.VISIBLE);
        if (mCallback != null) {
            mCallback.onPasswordCompleted(password);
        }
    }

    @Override
    public void onInput(String character) {
        if (PasswordKeyboard.DEL.equals(character)) {
            if (mPasswordBuffer.length() > 0) {
                mPasswordBuffer.delete(mPasswordBuffer.length() - 1, mPasswordBuffer.length());
            }
        } else if (PasswordKeyboard.DONE.equals(character)) {
            dismiss();
        } else {
            //密码输入错误状态,再次输入清除错误提示文字
            if (!passwordState) {
                if (!TextUtils.isEmpty(errorMsgTv.getText())) {
                    errorMsgTv.setText("");
                }
            }
            mPasswordBuffer.append(character);
        }
        passwordView.setPassword(mPasswordBuffer);
        if (mPasswordBuffer.length() == passwordView.getPasswordCount()) {
            startLoading(mPasswordBuffer);
        }
    }
    //密码对话框消失,清除密码输入
    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (mPasswordBuffer.length() > 0) {
            mPasswordBuffer.delete(0, mPasswordBuffer.length());
        }
    }
}

如果本文对你有帮助,请不吝啬你的喜欢。

上一篇下一篇

猜你喜欢

热点阅读