App需要支付場(chǎng)景的時(shí)候畸颅,都會(huì)讓用戶輸入密碼交易框,如果用系統(tǒng)或者第三方鍵盤(pán)可能導(dǎo)致密碼泄露方援。因此没炒,比較多的App會(huì)自定義密碼輸入鍵盤(pán)來(lái)提供安全性。本文依照支付寶密碼輸入界面來(lái)設(shè)計(jì)犯戏,同時(shí)提供隨機(jī)鍵盤(pán)功能送火。
項(xiàng)目地址:Github
看效果圖
模擬器上,會(huì)導(dǎo)致線條繪制模糊先匪。真機(jī)運(yùn)行效果更棒种吸。
數(shù)字密碼鍵盤(pán)安全級(jí)別
低:系統(tǒng)提供鍵盤(pán)或者第三方輸入法鍵盤(pán)。
中:自定義鍵盤(pán)呀非,但不隨機(jī)鍵盤(pán)數(shù)字坚俗。
高:自定義鍵盤(pán)镜盯,且隨機(jī)鍵盤(pán)數(shù)字。
數(shù)字密碼鍵盤(pán)實(shí)現(xiàn)原理
鍵盤(pán)實(shí)現(xiàn)的原理大致有兩種方法猖败。
1.利用系統(tǒng)提供的KeyboardView來(lái)完成速缆。
2.另外一種就是自定義View來(lái)完成鍵盤(pán)繪制。
本文采取的自定義View方式繪制鍵盤(pán)恩闻。
因?yàn)閿?shù)字鍵盤(pán)是九宮格的排列艺糜,所以首先考慮使用GridLayout。
因?yàn)镚ridLayout并不提供均勻分布的功能幢尚,所以我們得重新填充Child View破停。
解決思路如下:
1.填充鍵盤(pán)Key。
2.繪制鍵盤(pán)之間的分割線尉剩。
3.完成鍵盤(pán)Key點(diǎn)擊事件監(jiān)聽(tīng)真慢。
4.輸出鍵盤(pán)密碼的輸入。
看鍵盤(pán)源碼
public class PasswordKeyboard extends GridLayout implements View.OnClickListener, View.OnTouchListener {
public static final String DEL = "刪除";
public static final String DONE = "OK";
//因?yàn)閁ED是給的是iPhone設(shè)計(jì)稿,所以是按照等比的思想設(shè)置鍵盤(pán)Key的高度和寬度
private static final int IPHONE = 779;
//每個(gè)鍵盤(pán)Key的寬度,為屏幕寬度的三分之一
private int keyWidth = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth() / 3;
//每個(gè)鍵盤(pán)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集合存儲(chǔ)Key,方便每次輸錯(cuò)都能再次隨機(jī)數(shù)字鍵盤(pán)
private final List<Button> keyButtons = new ArrayList<>();
private WorkHandler mWorkHandler;
private static final int DELETE = 1;
//WorkHandler 用于處理長(zhǎng)按"刪除"Key時(shí),執(zhí)行重復(fù)刪除操作边涕。
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);
}
//重新設(shè)置鍵盤(pán)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() {
//必須設(shè)置調(diào)用該方法,不然onDraw方法不執(zhí)行晤碘。如果ViewGroup沒(méi)有背景,則其onDraw方法不執(zhí)行
setWillNotDraw(false);
if (getChildCount() > 0) {
keyButtons.clear();
removeAllViews();
}
//獲取隨機(jī)鍵盤(pán)數(shù)字的字符串
List<String> keyList = randomKeys(10);
//填充鍵盤(pán)Key,用Button來(lái)完成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));
//監(jiān)聽(tīng)"刪除"的長(zhǎng)按監(jiān)聽(tīng)事件,完成重復(fù)刪除操作
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) {
//密碼字符輸出回調(diào)
if (mListener != null) {
if (DONE.equals(character)) {
mListener.onInput(DONE);
} else if (DEL.equals(character)) {
mListener.onInput(DEL);
} else {
mListener.onInput(character);
}
}
}
//生產(chǎn)鍵盤(pán)Key隨機(jī)數(shù)字
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個(gè)位置,是個(gè)無(wú)操作的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);
}
}
密碼顯示框
因?yàn)椴荒苊魑娘@示輸入,所以我們用“●”代替每位密碼功蜓。自定義密碼顯示框比較簡(jiǎn)單园爷,直接采取繼承View方式完成。
解決思路如下式撼。
1.支持密碼位數(shù)設(shè)置童社。
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);
//支持某些屬性設(shè)置,比如密碼位數(shù),邊框顏色美浦、寬度,"●"的顏色弦赖、大小
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);
//設(shè)置輸入框圓角邊框
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();
//繪制每個(gè)"●"之間的分割線
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;
}
//支持密碼位數(shù)設(shè)置
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;
}
}
進(jìn)度條繪制
支付寶的驗(yàn)證密碼過(guò)程的進(jìn)度條是采取material design風(fēng)格,不過(guò)做了特殊動(dòng)畫(huà)效果浦辨,當(dāng)驗(yàn)證密碼正確的時(shí)候蹬竖,出現(xiàn)打“??”的動(dòng)畫(huà)。需解決問(wèn)題如下流酬。
1.material design進(jìn)度條旋轉(zhuǎn)的動(dòng)畫(huà)币厕。
2.停止旋轉(zhuǎn)動(dòng)畫(huà),開(kāi)始打“??”動(dòng)畫(huà)芽腾。
3.打“??”動(dòng)畫(huà)完成的回調(diào)旦装。
看源碼
進(jìn)度條旋轉(zhuǎn)動(dòng)畫(huà)過(guò)程,是參考網(wǎng)上一個(gè)例子摊滔,具體出處忘記了阴绢。若原作者看見(jiàn)店乐,請(qǐng)見(jiàn)諒。
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;
//默認(rèn)的動(dòng)畫(huà)時(shí)間
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;
//是否需要開(kāi)始繪制對(duì)勾
private boolean isNeedTick = false;
private int mResize;
private TickAnimation mTickAnimation;
//判斷"對(duì)勾"動(dòng)畫(huà)是否過(guò)半,"對(duì)勾"由兩條線繪制而成旱函。
private boolean isAnimationOverHalf = false;
//圓形進(jìn)度條的半徑
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);
//對(duì)勾動(dòng)畫(huà)監(jiān)聽(tīng)
mTickAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
//當(dāng)對(duì)勾動(dòng)畫(huà)完成后,延遲一秒回掉,不然動(dòng)畫(huà)效果不明顯
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);
}
//對(duì)勾動(dòng)畫(huà)完成回調(diào)
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) {
//補(bǔ)全圓
arcPaint();
canvas.drawArc(arcRectF, startAngle + incrementAngele + sweepAngle, 360 - sweepAngle, false, mPaint);
linePaint();
//畫(huà)第一根線
canvas.drawLine(startX1, startY1, stopX1, stopY1, mPaint);
if (isAnimationOverHalf) {
//-2 +2 是為了兩根線盡可能靠攏
canvas.drawLine(stopX1 - 2, stopY1 + 2, stopX2, stopY2, mPaint);
}
}
}
//對(duì)勾動(dòng)畫(huà)
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();
}
/**
* 進(jìn)度條旋轉(zhuǎn)的動(dòng)畫(huà)
*/
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;
}
//清除動(dòng)畫(huà)
private void cancelAnimator() {
if (animatorSet != null) {
animatorSet.cancel();
isNeedTick = true;
}
}
public void setSuccessfullyStatus() {
if (animatorSet != null) {
animatorSet.cancel();
isNeedTick = true;
startAnimation(mTickAnimation);
}
}
//重新setVisibility方法响巢,當(dāng)View不可見(jiàn)停止動(dòng)畫(huà),及時(shí)釋放資源棒妨。
@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();
}
}
仿支付寶密碼輸入對(duì)話框
所有自定義控件完成踪古,最后就是組裝的過(guò)程。本文采用DialogFragment進(jìn)行封裝券腔。同時(shí)伏穆,提供各個(gè)點(diǎn)擊事件的回調(diào)。
public interface Callback {
//忘記密碼
void onForgetPassword();
//密碼輸入完成纷纫,比如密碼長(zhǎng)度為六位枕扫,當(dāng)密碼輸入六位時(shí)候,直接 發(fā)出密碼校驗(yàn)請(qǐng)求
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);
//設(shè)置密碼長(zhǎng)度
if (passwordCount > 0) {
passwordView.setPasswordCount(passwordCount);
}
numberKeyBoard = (PasswordKeyboard) view.findViewById(R.id.password_keyboard);
numberKeyBoard.setOnPasswordInputListener(this);
cancelTv.setOnClickListener(this);
forgetPasswordTv.setOnClickListener(this);
}
/**
* 設(shè)置密碼長(zhǎng)度
*/
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();
}
}
//開(kāi)始進(jìn)度條旋轉(zhuǎn)
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 {
//密碼輸入錯(cuò)誤狀態(tài)辱魁,再次輸入清除錯(cuò)誤提示文字
if (!passwordState) {
if (!TextUtils.isEmpty(errorMsgTv.getText())) {
errorMsgTv.setText("");
}
}
mPasswordBuffer.append(character);
}
passwordView.setPassword(mPasswordBuffer);
if (mPasswordBuffer.length() == passwordView.getPasswordCount()) {
startLoading(mPasswordBuffer);
}
}
//密碼對(duì)話框消失烟瞧,清除密碼輸入
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mPasswordBuffer.length() > 0) {
mPasswordBuffer.delete(0, mPasswordBuffer.length());
}
}
}
如果本文對(duì)你有幫助,請(qǐng)不吝嗇你的喜歡染簇。