天天看点

android 手势密码 开发,Android自定义控件实现手势密码

Android手势解锁密码效果图

android 手势密码 开发,Android自定义控件实现手势密码

首先呢想写这个手势密码的想法呢,完全是凭空而来的,然后笔者就花了一天时间弄出来了。本以为这个东西很简单,实际上手的时候发现,还有很多逻辑需要处理,稍不注意就容易乱套。写个UI效果图大约只花了3个小时,但是处理逻辑就处理了2个小时!废话不多说,下面开始讲解。

楼主呢,自己比较自定义控件,什么东西都掌握在自己的手里感觉那是相当不错(对于赶工期的小伙瓣儿们还是别手贱了,非常容易掉坑),一有了这个目标,我就开始构思实现方式。

1、整个自定义控件是继承View还是SurfaceView呢?我的经验告诉我:需要一直不断绘制的最好继承SurfaceView,而需要频繁与用户交互的最好就继承View。(求大神来打脸)

2、为了实现控件的屏幕适配性,当然必须重写onMeasure方法,然后在onDraw方法中进行绘制。

3、面向对象性:这个控件其实由两个对象组成:1、9个圆球;2、圆球之间的连线。

4、仔细观察圆球的特征:普通状态是白色、touch状态是蓝色、错误状态是红色、整体分为外围空心圆和内实心圆、所代表的位置信息(密码值)

5、仔细观察连线的特征:普通状态为蓝色、错误状态为红色、始终连接两个圆的中心、跟随手指移动而拓展连线、连线之间未点亮的圆球也要点亮。

6、通过外露参数来设置圆球的颜色、大小等等

7、通过上面的分析,真个控件可模块化为三个任务:onMeasure计算控件宽高以及小球半径、onDraw绘制小球与连线、onTouchEvent控制绘制变化。

我把整个源码分为三个类文件:LockView、Circle、Util,其中LockView代表整个控件,Circle代表小圆球、Util封装工具方法(Path因为太简单就没封装,若有代码洁癖请自行封装),下面展示Util类的源代码。

public class Util{

private static final String SP_NAME = "LOCKVIEW";

private static final String SP_KEY = "PASSWORD";

public static void savePwd(Context mContext ,List password){

SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);

sp.edit().putString(SP_KEY, listToString(password)).commit();

}

public static String getPwd(Context mContext){

SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);

return sp.getString(SP_KEY, "");

}

public static void clearPwd(Context mContext){

SharedPreferences sp = mContext.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);

sp.edit().remove(SP_KEY).commit();

}

public static String listToString(List lists){

StringBuffer sb = new StringBuffer();

for(int i = 0; i < lists.size(); i++){

sb.append(lists.get(i));

}

return sb.toString();

}

public static List stringToList(String string){

List lists = new ArrayList<>();

for(int i = 0; i < string.length(); i++){

lists.add(Integer.parseInt(string.charAt(i) + ""));

}

return lists;

}

}

这个工具方法其实很简单,就是对SharedPreferences的一个读写,还有就是List与String类型的互相转换。这里就不描述了。下面展示Circle的源码

public class Circle{

//默认值

public static final int DEFAULT_COLOR = Color.WHITE;

public static final int DEFAULT_BOUND = 5;

public static final int DEFAULT_CENTER_BOUND = 15;

//状态值

public static final int STATUS_DEFAULT = 0;

public static final int STATUS_TOUCH = 1;

public static final int STATUS_SUCCESS = 2;

public static final int STATUS_FAILED = 3;

//圆形的中点X、Y坐标

private int centerX;

private int centerY;

//圆形的颜色值

private int colorDefault = DEFAULT_COLOR;

private int colorSuccess;

private int colorFailed;

//圆形的宽度

private int bound = DEFAULT_BOUND;

//中心的宽度

private int centerBound = DEFAULT_CENTER_BOUND;

//圆形的半径

private int radius;

//圆形的状态

private int status = STATUS_DEFAULT;

//圆形的位置

private int position;

public Circle(int centerX, int centerY, int colorSuccess, int colorFailed, int radius, int position){

super();

this.centerX = centerX;

this.centerY = centerY;

this.colorSuccess = colorSuccess;

this.colorFailed = colorFailed;

this.radius = radius;

this.position = position;

}

public Circle(int centerX, int centerY, int colorDefault, int colorSuccess, int colorFailed, int bound,

int centerBound, int radius, int status, int position){

super();

this.centerX = centerX;

this.centerY = centerY;

this.colorDefault = colorDefault;

this.colorSuccess = colorSuccess;

this.colorFailed = colorFailed;

this.bound = bound;

this.centerBound = centerBound;

this.radius = radius;

this.status = status;

this.position = position;

}

public int getCenterX(){

return centerX;

}

public void setCenterX(int centerX){

this.centerX = centerX;

}

public int getCenterY(){

return centerY;

}

public void setCenterY(int centerY){

this.centerY = centerY;

}

public int getColorDefault(){

return colorDefault;

}

public void setColorDefault(int colorDefault){

this.colorDefault = colorDefault;

}

public int getColorSuccess(){

return colorSuccess;

}

public void setColorSuccess(int colorSuccess){

this.colorSuccess = colorSuccess;

}

public int getColorFailed(){

return colorFailed;

}

public void setColorFailed(int colorFailed){

this.colorFailed = colorFailed;

}

public int getBound(){

return bound;

}

public void setBound(int bound){

this.bound = bound;

}

public int getCenterBound(){

return centerBound;

}

public void setCenterBound(int centerBound){

this.centerBound = centerBound;

}

public int getRadius(){

return radius;

}

public void setRadius(int radius){

this.radius = radius;

}

public int getStatus(){

return status;

}

public void setStatus(int status){

this.status = status;

}

public int getPosition(){

return position;

}

public void setPosition(int position){

this.position = position;

}

public void changeStatus(int status){

this.status = status;

}

public void draw(Canvas canvas ,Paint paint){

switch(status){

case STATUS_DEFAULT:

paint.setColor(colorDefault);

break;

case STATUS_TOUCH:

case STATUS_SUCCESS:

paint.setColor(colorSuccess);

break;

case STATUS_FAILED:

paint.setColor(colorFailed);

break;

default:

paint.setColor(colorDefault);

break;

}

paint.setStyle(Paint.Style.FILL);

//绘制中心实心圆

canvas.drawCircle(centerX, centerY, centerBound, paint);

//绘制空心圆

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(bound);

canvas.drawCircle(centerX, centerY, radius, paint);

}

}

这个Circle其实也非常简单。上面定义的成员变量一眼便明,并且有注释。重点在最后的draw方法,首先呢根据当前圆球的不同状态设置不同的颜色值,然后绘制中心的实心圆,再绘制外围的空心圆。所有的参数要么是外界传递,要么是默认值。(ps:面向对象真的非常有用,解耦良好的代码写起来也舒服看起来也舒服)。

最后的重点来了,LockView的源码,首先贴源码,然后再针对性讲解。

public class LockView extends View{

private static final int COUNT_PER_RAW = 3;

private static final int DURATION = 1500;

private static final int MIN_PWD_NUMBER = 6;

//@Fields STATUS_NO_PWD : 当前没有保存密码

public static final int STATUS_NO_PWD = 0;

//@Fields STATUS_RETRY_PWD : 需要再输入一次密码

public static final int STATUS_RETRY_PWD = 1;

//@Fields STATUS_SAVE_PWD : 成功保存密码

public static final int STATUS_SAVE_PWD = 2;

//@Fields STATUS_SUCCESS_PWD : 成功验证密码

public static final int STATUS_SUCCESS_PWD = 3;

//@Fields STATUS_FAILED_PWD : 验证密码失败

public static final int STATUS_FAILED_PWD = 4;

//@Fields STATUS_ERROR : 输入密码长度不够

public static final int STATUS_ERROR = 5;

private int width;

private int height;

private int padding = 0;

private int colorSuccess = Color.BLUE;

private int colorFailed = Color.RED;

private int minPwdNumber = MIN_PWD_NUMBER;

private List circles = new ArrayList<>();

private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Path mPath = new Path();

private Path backupsPath = new Path();

private List result = new ArrayList<>();

private int status = STATUS_NO_PWD;

private OnLockListener listener;

private Handler handler = new Handler();

public LockView(Context context, AttributeSet attrs, int defStyle){

super(context, attrs, defStyle);

initStatus();

}

public LockView(Context context, AttributeSet attrs){

super(context, attrs);

initStatus();

}

public LockView(Context context){

super(context);

initStatus();

}

public void initStatus(){

if(TextUtils.isEmpty(Util.getPwd(getContext()))){

status = STATUS_NO_PWD;

}else{

status = STATUS_SAVE_PWD;

}

}

public int getCurrentStatus(){

return status;

}

public LockView initParam(int padding ,int colorSuccess ,int colorFailed ,int minPwdNumber){

this.padding = padding;

this.colorSuccess = colorSuccess;

this.colorFailed = colorFailed;

this.minPwdNumber = minPwdNumber;

init();

return this;

}

private void init(){

int circleRadius = (width - (COUNT_PER_RAW + 1) * padding) / COUNT_PER_RAW /2;

if(circles.size() == 0){

for(int i = 0; i < COUNT_PER_RAW * COUNT_PER_RAW; i++){

createCircles(circleRadius, i);

}

}else{

for(int i = 0; i < COUNT_PER_RAW * COUNT_PER_RAW; i++){

updateCircles(circles.get(i), circleRadius);

}

}

}

private void createCircles(int radius, int position){

int centerX = (position % 3 + 1) * padding + (position % 3 * 2 + 1) * radius;

int centerY = (position / 3 + 1) * padding + (position / 3 * 2 + 1) * radius;

Circle circle = new Circle(centerX, centerY, colorSuccess, colorFailed, radius, position);

circles.add(circle);

}

private void updateCircles(Circle circle ,int radius){

int centerX = (circle.getPosition() % 3 + 1) * padding + (circle.getPosition() % 3 * 2 + 1) * radius;

int centerY = (circle.getPosition() / 3 + 1) * padding + (circle.getPosition() / 3 * 2 + 1) * radius;

circle.setCenterX(centerX);

circle.setCenterY(centerY);

circle.setRadius(radius);

circle.setColorSuccess(colorSuccess);

circle.setColorFailed(colorFailed);

}

@Override

protected void onDraw(Canvas canvas){

init();

//绘制圆

for(int i = 0; i < circles.size() ;i++){

circles.get(i).draw(canvas, mPaint);

}

if(result.size() != 0){

//绘制Path

Circle temp = circles.get(result.get(0));

mPaint.setColor(temp.getStatus() == Circle.STATUS_FAILED ? colorFailed : colorSuccess);

mPaint.setStrokeWidth(Circle.DEFAULT_CENTER_BOUND);

canvas.drawPath(mPath, mPaint);

}

}

@Override

public boolean onTouchEvent(MotionEvent event){

switch(event.getAction()){

case MotionEvent.ACTION_DOWN:

backupsPath.reset();

for(int i = 0; i < circles.size() ;i++){

Circle circle = circles.get(i);

if(event.getX() >= circle.getCenterX() - circle.getRadius()

&& event.getX() <= circle.getCenterX() + circle.getRadius()

&& event.getY() >= circle.getCenterY() - circle.getRadius()

&& event.getY() <= circle.getCenterY() + circle.getRadius()){

circle.setStatus(Circle.STATUS_TOUCH);

//将这个点放入Path

backupsPath.moveTo(circle.getCenterX(), circle.getCenterY());

//放入结果

result.add(circle.getPosition());

break;

}

}

invalidate();

return true;

case MotionEvent.ACTION_MOVE:

for(int i = 0; i < circles.size() ;i++){

Circle circle = circles.get(i);

if(event.getX() >= circle.getCenterX() - circle.getRadius()

&& event.getX() <= circle.getCenterX() + circle.getRadius()

&& event.getY() >= circle.getCenterY() - circle.getRadius()

&& event.getY() <= circle.getCenterY() + circle.getRadius()){

if(!result.contains(circle.getPosition())){

circle.setStatus(Circle.STATUS_TOUCH);

//首先判断是否连线中间也有满足条件的圆

Circle lastCircle = circles.get(result.get(result.size() - 1));

int cx = (lastCircle.getCenterX() + circle.getCenterX()) / 2;

int cy = (lastCircle.getCenterY() + circle.getCenterY()) / 2;

for(int j = 0; j < circles.size(); j++){

Circle tempCircle = circles.get(j);

if(cx >= tempCircle.getCenterX() - tempCircle.getRadius()

&& cx <= tempCircle.getCenterX() + tempCircle.getRadius()

&& cy >= tempCircle.getCenterY() - tempCircle.getRadius()

&& cy <= tempCircle.getCenterY() + tempCircle.getRadius()){

//处理满足条件的圆

backupsPath.lineTo(tempCircle.getCenterX(), tempCircle.getCenterY());

//放入结果

tempCircle.setStatus(Circle.STATUS_TOUCH);

result.add(tempCircle.getPosition());

}

}

//处理现在的圆

backupsPath.lineTo(circle.getCenterX(), circle.getCenterY());

//放入结果

circle.setStatus(Circle.STATUS_TOUCH);

result.add(circle.getPosition());

break;

}

}

}

mPath.reset();

mPath.addPath(backupsPath);

mPath.lineTo(event.getX(), event.getY());

invalidate();

break;

case MotionEvent.ACTION_UP:

mPath.reset();

mPath.addPath(backupsPath);

invalidate();

if(result.size() < minPwdNumber){

if(listener != null){

listener.onError();

}

if(status == STATUS_RETRY_PWD){

Util.clearPwd(getContext());

}

status = STATUS_ERROR;

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}else{

if(status == STATUS_NO_PWD){ //当前没有密码

//保存密码,重新录入

Util.savePwd(getContext(), result);

status = STATUS_RETRY_PWD;

if(listener != null){

listener.onTypeInOnce(Util.listToString(result));

}

}else if(status == STATUS_RETRY_PWD){ //需要重新绘制密码

//判断两次输入是否相等

if(Util.getPwd(getContext()).equals(Util.listToString(result))){

status = STATUS_SAVE_PWD;

if(listener != null){

listener.onTypeInTwice(Util.listToString(result), true);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_SUCCESS);

}

}else{

status = STATUS_NO_PWD;

Util.clearPwd(getContext());

if(listener != null){

listener.onTypeInTwice(Util.listToString(result), false);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}

}else if(status == STATUS_SAVE_PWD){ //验证密码

//判断密码是否正确

if(Util.getPwd(getContext()).equals(Util.listToString(result))){

status = STATUS_SUCCESS_PWD;

if(listener != null){

listener.onUnLock(Util.listToString(result), true);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_SUCCESS);

}

}else{

status = STATUS_FAILED_PWD;

if(listener != null){

listener.onUnLock(Util.listToString(result), false);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}

}

}

invalidate();

handler.postDelayed(new Runnable(){

@Override

public void run(){

result.clear();

mPath.reset();

backupsPath.reset();

// initStatus();

// 重置下状态

if(status == STATUS_SUCCESS_PWD || status == STATUS_FAILED_PWD){

status = STATUS_SAVE_PWD;

}else if(status == STATUS_ERROR){

initStatus();

}

for(int i = 0; i < circles.size(); i++){

circles.get(i).setStatus(Circle.STATUS_DEFAULT);

}

invalidate();

}

}, DURATION);

break;

default:

break;

}

return super.onTouchEvent(event);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){

width = MeasureSpec.getSize(widthMeasureSpec);

height = width - getPaddingLeft() - getPaddingRight() + getPaddingTop() + getPaddingBottom();

setMeasuredDimension(width, height);

}

public void setOnLockListener(OnLockListener listener){

this.listener = listener;

}

public interface OnLockListener{

void onTypeInOnce(String input);

void onTypeInTwice(String input ,boolean isSuccess);

void onUnLock(String input ,boolean isSuccess);

void onError();

}

}

好了,逐次讲解。

首先是对status的初始化,其实在static域我已经申明了6个状态,分别是:

//当前没有保存密码

public static final int STATUS_NO_PWD = 0;

//需要再输入一次密码

public static final int STATUS_RETRY_PWD = 1;

//成功保存密码

public static final int STATUS_SAVE_PWD = 2;

//成功验证密码

public static final int STATUS_SUCCESS_PWD = 3;

//验证密码失败

public static final int STATUS_FAILED_PWD = 4;

//输入密码长度不够

public static final int STATUS_ERROR = 5;

在刚初始化的时候,就初始化当前的状态,初始化状态就只有2个状态:有密码、无密码。

public void initStatus(){

if(TextUtils.isEmpty(Util.getPwd(getContext()))){

status = STATUS_NO_PWD;

}else{

status = STATUS_SAVE_PWD;

}

}

public int getCurrentStatus(){

return status;

}

然后就是通过外界的设置初始化一些参数(若不调用initParam方法,则采用默认值):

public LockView initParam(int padding ,int colorSuccess ,int colorFailed ,int minPwdNumber){

this.padding = padding;

this.colorSuccess = colorSuccess;

this.colorFailed = colorFailed;

this.minPwdNumber = minPwdNumber;

init();

return this;

}

private void init(){

int circleRadius = (width - (COUNT_PER_RAW + 1) * padding) / COUNT_PER_RAW /2;

if(circles.size() == 0){

for(int i = 0; i < COUNT_PER_RAW * COUNT_PER_RAW; i++){

createCircles(circleRadius, i);

}

}else{

for(int i = 0; i < COUNT_PER_RAW * COUNT_PER_RAW; i++){

updateCircles(circles.get(i), circleRadius);

}

}

}

上述代码主要根据设置的padding值,计算出小球的大小,然后判断是否是初始化小球,还是更新小球。

private void createCircles(int radius, int position){

int centerX = (position % 3 + 1) * padding + (position % 3 * 2 + 1) * radius;

int centerY = (position / 3 + 1) * padding + (position / 3 * 2 + 1) * radius;

Circle circle = new Circle(centerX, centerY, colorSuccess, colorFailed, radius, position);

circles.add(circle);

}

private void updateCircles(Circle circle ,int radius){

int centerX = (circle.getPosition() % 3 + 1) * padding + (circle.getPosition() % 3 * 2 + 1) * radius;

int centerY = (circle.getPosition() / 3 + 1) * padding + (circle.getPosition() / 3 * 2 + 1) * radius;

circle.setCenterX(centerX);

circle.setCenterY(centerY);

circle.setRadius(radius);

circle.setColorSuccess(colorSuccess);

circle.setColorFailed(colorFailed);

}

别忘了上面的方法依赖一个width值,这个值是在onMeasure中计算出来的

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){

width = MeasureSpec.getSize(widthMeasureSpec);

height = width - getPaddingLeft() - getPaddingRight() + getPaddingTop() + getPaddingBottom();

setMeasuredDimension(width, height);

}

然后就是绘制方法了,因为我们的高度解耦性,本应该非常复杂的onDraw方法,却如此简单。就只绘制了小球和路径。

@Override

protected void onDraw(Canvas canvas){

init();

//绘制圆

for(int i = 0; i < circles.size() ;i++){

circles.get(i).draw(canvas, mPaint);

}

if(result.size() != 0){

//绘制Path

Circle temp = circles.get(result.get(0));

mPaint.setColor(temp.getStatus() == Circle.STATUS_FAILED ? colorFailed : colorSuccess);

mPaint.setStrokeWidth(Circle.DEFAULT_CENTER_BOUND);

canvas.drawPath(mPath, mPaint);

}

}

控件是需要和外界进行交互的,我喜欢的方法就是自定义监听器,然后接口回调。

public void setOnLockListener(OnLockListener listener){

this.listener = listener;

}

public interface OnLockListener{

void onTypeInOnce(String input);

void onTypeInTwice(String input ,boolean isSuccess);

void onUnLock(String input ,boolean isSuccess);

void onError();

}

最后最最最重要的一个部分来了,onTouchEvent方法,这个方法其实也可以分为三个部分讲解:down事件、move事件和up事件。首先贴出down事件代码

case MotionEvent.ACTION_DOWN:

backupsPath.reset();

for(int i = 0; i < circles.size() ;i++){

Circle circle = circles.get(i);

if(event.getX() >= circle.getCenterX() - circle.getRadius()

&& event.getX() <= circle.getCenterX() + circle.getRadius()

&& event.getY() >= circle.getCenterY() - circle.getRadius()

&& event.getY() <= circle.getCenterY() + circle.getRadius()){

circle.setStatus(Circle.STATUS_TOUCH);

//将这个点放入Path

backupsPath.moveTo(circle.getCenterX(), circle.getCenterY());

//放入结果

result.add(circle.getPosition());

break;

}

}

invalidate();

return true;

也就是对按下的x、y坐标进行判断,是否属于我们的小球范围内,若属于,则放入路径集合、更改状态、加入密码结果集。这里别忘了return true,大家都知道吧。

然后是move事件,move事件主要做三件事情:变更小球的状态、添加到路径集合、对路径覆盖的未点亮小球进行点亮。代码有详细注释就不过多讲解了。

case MotionEvent.ACTION_MOVE:

for(int i = 0; i < circles.size() ;i++){

Circle circle = circles.get(i);

if(event.getX() >= circle.getCenterX() - circle.getRadius()

&& event.getX() <= circle.getCenterX() + circle.getRadius()

&& event.getY() >= circle.getCenterY() - circle.getRadius()

&& event.getY() <= circle.getCenterY() + circle.getRadius()){

if(!result.contains(circle.getPosition())){

circle.setStatus(Circle.STATUS_TOUCH);

//首先判断是否连线中间也有满足条件的圆

Circle lastCircle = circles.get(result.get(result.size() - 1));

int cx = (lastCircle.getCenterX() + circle.getCenterX()) / 2;

int cy = (lastCircle.getCenterY() + circle.getCenterY()) / 2;

for(int j = 0; j < circles.size(); j++){

Circle tempCircle = circles.get(j);

if(cx >= tempCircle.getCenterX() - tempCircle.getRadius()

&& cx <= tempCircle.getCenterX() + tempCircle.getRadius()

&& cy >= tempCircle.getCenterY() - tempCircle.getRadius()

&& cy <= tempCircle.getCenterY() + tempCircle.getRadius()){

//处理满足条件的圆

backupsPath.lineTo(tempCircle.getCenterX(), tempCircle.getCenterY());

//放入结果

tempCircle.setStatus(Circle.STATUS_TOUCH);

result.add(tempCircle.getPosition());

}

}

//处理现在的圆

backupsPath.lineTo(circle.getCenterX(), circle.getCenterY());

//放入结果

circle.setStatus(Circle.STATUS_TOUCH);

result.add(circle.getPosition());

break;

}

}

}

mPath.reset();

mPath.addPath(backupsPath);

mPath.lineTo(event.getX(), event.getY());

invalidate();

break;

这里我用了两个Path对象,backupsPath用于只存放小球的中点坐标,mPath不仅要存储小球的中点坐标,还要存储当前手指触碰坐标,为了实现连线跟随手指运动的效果。

最后是up事件,这里有太多复杂的状态转换,我估计文字讲解是描述不清的,大家还是看源代码吧。

case MotionEvent.ACTION_UP:

mPath.reset();

mPath.addPath(backupsPath);

invalidate();

if(result.size() < minPwdNumber){

if(listener != null){

listener.onError();

}

if(status == STATUS_RETRY_PWD){

Util.clearPwd(getContext());

}

status = STATUS_ERROR;

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}else{

if(status == STATUS_NO_PWD){ //当前没有密码

//保存密码,重新录入

Util.savePwd(getContext(), result);

status = STATUS_RETRY_PWD;

if(listener != null){

listener.onTypeInOnce(Util.listToString(result));

}

}else if(status == STATUS_RETRY_PWD){ //需要重新绘制密码

//判断两次输入是否相等

if(Util.getPwd(getContext()).equals(Util.listToString(result))){

status = STATUS_SAVE_PWD;

if(listener != null){

listener.onTypeInTwice(Util.listToString(result), true);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_SUCCESS);

}

}else{

status = STATUS_NO_PWD;

Util.clearPwd(getContext());

if(listener != null){

listener.onTypeInTwice(Util.listToString(result), false);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}

}else if(status == STATUS_SAVE_PWD){ //验证密码

//判断密码是否正确

if(Util.getPwd(getContext()).equals(Util.listToString(result))){

status = STATUS_SUCCESS_PWD;

if(listener != null){

listener.onUnLock(Util.listToString(result), true);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_SUCCESS);

}

}else{

status = STATUS_FAILED_PWD;

if(listener != null){

listener.onUnLock(Util.listToString(result), false);

}

for(int i = 0; i < result.size(); i++){

circles.get(result.get(i)).setStatus(Circle.STATUS_FAILED);

}

}

}

}

invalidate();

handler.postDelayed(new Runnable(){

@Override

public void run(){

result.clear();

mPath.reset();

backupsPath.reset();

// initStatus();

// 重置下状态

if(status == STATUS_SUCCESS_PWD || status == STATUS_FAILED_PWD){

status = STATUS_SAVE_PWD;

}else if(status == STATUS_ERROR){

initStatus();

}

for(int i = 0; i < circles.size(); i++){

circles.get(i).setStatus(Circle.STATUS_DEFAULT);

}

invalidate();

}

}, DURATION);

break;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。