基于Android的图案解锁实现

来源:互联网 发布:四海金戈 全武将数据 编辑:程序博客网 时间:2024/04/29 20:56
备注说明:通过之前的“Android图案解锁”学习,特意将实现的思路给理出来、记录下来,作为自己的学习总结。文中存在不对之处,请大家踊跃指出,转载请标明出处。

实现思路:
1、自定义LockPatterView控件,定义九宫格点的类型,实现绘制九宫格布局。
2、重写onTouchEvent()事件,完成选中点的绘制。
3、绘制两点之间的连接线。
4、图案密码的设置与验证。
效果展示:
这里写图片描述

一、自定义LockPatterView控件,定义九宫格点的类型,实现绘制九宫格布局。

1、定义九宫格中的点类型。

    /**自定义九宫格点类型*/    public class Point{        public static final int STATE_NORMAL=0;//正常时        public static final int STATE_PRESS=1;//选中时        public static final int STATE_ERROR=2;//错误时        public float x,y;//点的坐标        public int state;//点的状态        public Point(float x,float y){            this.x=x;            this.y=y;        }    }

2、初始化九宫格的点坐标

/**初始化点的数据*/    private void initPoints() {        //1.得到控件的布局        float width=getWidth();        float height=getHeight();        //2.得到横竖屏时的偏移量        if(width>height){//横屏时,高度充满整个控件            offsetX=(width-height)/2;//宽度居于控件中央显示            offsetY=0;            width=height;        }else{//竖屏时,宽度充满整个控件的宽度            offsetX=0;            offsetY=(width-height)/2;//高度居于控件中央显示            height=width;        }         //图片资源        bitmap_normal = BitmapFactory.decodeResource(getResources(), R.drawable.ic_point_normal);        bitmap_pressed = BitmapFactory.decodeResource(getResources(), R.drawable.ic_point_press);        bitmap_error = BitmapFactory.decodeResource(getResources(),  R.drawable.ic_point_error);        bitmap_line = BitmapFactory.decodeResource(getResources(),  R.drawable.ic_line_normal);        bitmap_line_error = BitmapFactory.decodeResource(getResources(),  R.drawable.ic_line_error);        //3.初始化九宫格点的坐标        for(int i=0;i<points.length;i++){            for(int j=0;j<points[i].length;j++){                 points[i][j]=new Point(width/4+j*width/4+offsetX,height/4+height/4*i+offsetY);            }        }        isInit=true;    }

3、将九宫格点绘制到画布上

/**将点画在画布上*/    private void points2Canvas(Canvas canvas) {        // TODO Auto-generated method stub        //3.绘制九宫格点        for(int i=0;i<points.length;i++){            for(int j=0;j<points[i].length;j++){                Point point=points[i][j];                if(point.state==Point.STATE_NORMAL){                    canvas.drawBitmap(bitmap_normal, point.x-bitmap_normal.getWidth()/2, point.y-bitmap_normal.getHeight()/2, paint);                }else if(point.state==Point.STATE_PRESS){                    canvas.drawBitmap(bitmap_pressed, point.x-bitmap_pressed.getWidth()/2, point.y-bitmap_pressed.getHeight()/2, paint);                }else{                    canvas.drawBitmap(bitmap_error, point.x-bitmap_error.getWidth()/2, point.y-bitmap_error.getHeight()/2, paint);                      }            }        }    }

4、最终效果
这里写图片描述

二、重写onTouchEvent()事件,完成选中点的绘制。

1、判断移动的点是否属于九宫格的点,如果是,则该点属于选中的点。

/**判断两点是否重合*/        public static boolean with(float pointX,float pointY,float r,float moveX,float moveY){            return Math.sqrt((pointX-moveX)*(pointX-moveX)+(pointY-moveY)*(pointY-moveY))<r;        }        /**检查移动的点是否属于九宫格的点*/    private Point checkPoints(){        for(int i=0;i<points.length;i++){            for(int j=0;j<points[i].length;j++){                Point point=points[i][j];                if(Point.with(point.x, point.y, bitmap_normal.getWidth()/2, moveX, moveY)){                    return point;                }            }        }        return null;    }

2、判断该点是否属于交叉点(之前已经添加过的点)。

    /**检查是否是交叉点*/    private boolean crossPoint(Point point){        return pointList.contains(point);    }

3、完成选中点的添加。

    private float moveX,moveY;//移动点的坐标    private boolean isSelect,isFinish;    private List<Point>pointList=new ArrayList<LockPatterView.Point>();    private static final int mMinPointCount=5;//最少绘制点数@Override    public boolean onTouchEvent(MotionEvent event) {        moveX=event.getX();        moveY=event.getY();        isFinish=false;        Point point=null;        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:            resetPoints();            point=checkPoints();            if(point!=null){                isSelect=true;            }            break;        case MotionEvent.ACTION_MOVE:            break;        case MotionEvent.ACTION_UP:            isFinish=true;            isSelect=false;            break;        }        //添加点        if(!isFinish&&isSelect&&point!=null){            if(crossPoint(point)){//是交叉点            }else{//新点                point.state=Point.STATE_PRESS;                pointList.add(point);            }        }        //绘制结束        if(isFinish){            if(pointList.size()==1){//只绘制一个点                resetPoints();            }else if(pointList.size()<mMinPointCount){//小于5个点时                errorPoints();            }else{//正确的点,用于之后作为密码使用            }        }        postInvalidate();//通知onDraw()方法,重新绘制        return true;//触摸事件能够继续执行下去    }

4、最终效果。
这里写图片描述

三、绘制两点之间的连线。

1、设置连接线的缩放。

/**判断两点之间的距离*/        public static double distance(Point a,Point b){            return Math.sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));        }            //得到线的长度        float linelength=(float) Point.distance(a, b);if(a.state==Point.STATE_PRESS){            //设置线的缩放              matrix.setScale(linelength / bitmap_line.getWidth(), 1);              //设置线的起始位置              matrix.postTranslate(a.x - bitmap_line.getWidth() / 2 , a.y - bitmap_line.getHeight() /2);              canvas.drawBitmap(bitmap_line, matrix, paint);        }else{             matrix.setScale(linelength / bitmap_line.getWidth(), 1);                matrix.postTranslate(a.x - bitmap_line.getWidth() / 2 , a.y - bitmap_line.getHeight() /2);             canvas.drawBitmap(bitmap_line_error, matrix, paint);        }

2、得到线的旋转角度

// 获取角度    public float getDegrees(Point pointA, Point pointB) { return (float) Math.toDegrees(Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x));    }

3、根据线的旋转角度以及线的长度,绘制出两点之间的连线。

/**画两点之间的连线*/    private void line2Canvas(Point a,Point b,Canvas canvas) {        // TODO Auto-generated method stub        //得到线的长度        float linelength=(float) Point.distance(a, b);        float degress = getDegrees(a,b);        canvas.rotate(degress, a.x, a.y);        if(a.state==Point.STATE_PRESS){            //设置线的缩放              matrix.setScale(linelength / bitmap_line.getWidth(), 1);              //设置线的起始位置              matrix.postTranslate(a.x - bitmap_line.getWidth() / 2 , a.y - bitmap_line.getHeight() /2);              canvas.drawBitmap(bitmap_line, matrix, paint);        }else{             matrix.setScale(linelength / bitmap_line.getWidth(), 1);                matrix.postTranslate(a.x - bitmap_line.getWidth() / 2 , a.y - bitmap_line.getHeight() /2);             canvas.drawBitmap(bitmap_line_error, matrix, paint);        }         canvas.rotate(-degress, a.x, a.y);    }

4、在交叉点或移动线的时候也需要绘制连接线。

    //画线         if(pointList.size()>0){             Point a=pointList.get(0);             for(int i=1;i<pointList.size();i++){                 Point b=pointList.get(i);                 line2Canvas(a,b,canvas);                 a=b;             }             if(isMoveNoPoint){//交叉点,连接线的时候                 line2Canvas(a,new Point(moveX,moveY),canvas);                }         }

5、最终效果
这里写图片描述
这里写图片描述

四、图案密码的设置与验证。

1、初始化密码参数。

   //初始化密码参数        int index = 1;        for(int i=0;i<points.length;i++){            for(int j=0;j<points[i].length;j++){                Point point=points[i][j];                point.index = index;                index++;            }        }

2、绘制图案后,设置密码。

  String passwordStr="";                    for(int i=0;i<pointList.size();i++){                    passwordStr+=pointList.get(i).index;                }

3、设置密码回调监听

/**     * 图案监听器     */    public static interface OnPatterChangeLister{        void onPatterChange(String passwordStr);        void onPatterStart(boolean isStart);    }    /**     * 设置图案监听器     * @param changeLister     */    public void SetOnPatterChangeLister(OnPatterChangeLister changeLister){        if (changeLister != null) {            this.onPatterChangeLister = changeLister;        }    }

4、对绘制正确、绘制错误时设置图案监听返回。

//绘制结束        if(isFinis){            if(pointList.size()==1){                resetPoint();            }else if(pointList.size()<POINT_SIZE&&pointList.size()>0){                errorPoint();                onPatterChangeLister.onPatterChange(null);            }else{                if(onPatterChangeLister!=null){                    String passwordStr="";                    for(int i=0;i<pointList.size();i++){                    passwordStr+=pointList.get(i).index;                }                    onPatterChangeLister.onPatterChange(passwordStr);                }            }        }

5、根据图案密码回调进行相应处理。

mLockPatterView.SetOnPatterChangeLister(new LockPatterView.OnPatterChangeLister() {            @Override            public void onPatterChange(String passwordStr) {                if (passwordStr != null) {                    if(pwdStr.equals("")){//设置密码                        if(setPwd.equals("")){//第一次设置密码                            setPwd=passwordStr;                            pwdTv_.setText("请绘制确认密码");                            mLockPatterView.resetPoint();                        }else{                            if(setPwd.equals(passwordStr)){                                sharedPreferences.edit().putString("pwd",setPwd).commit();                                Toast.makeText(MainActivity.this, "密码设置成功", Toast.LENGTH_LONG).show();                                finish();                            }else{                                setPwd="";                                pwdTv_.setText("两次密码绘制不一致,请重新绘制");                                mLockPatterView.resetPoint();                            }                        }                    }else{//验证密码                        if(pwdStr.equals(passwordStr)){                            Toast.makeText(MainActivity.this, "恭喜你,密码输入正确", Toast.LENGTH_LONG).show();                            pwdStr="";                            mLockPatterView.resetPoint();                            pwdTv_.setText("请先绘制图案密码");                        }else{                            pwdTv_.setText("密码绘制错误,请重新绘制");                            mLockPatterView.resetPoint();                        }                    }                } else {                    pwdTv_.setText("至少5个图案");                }            }            @Override            public void onPatterStart(boolean isStart) {            }        });

6、最终效果
这里写图片描述

五、源码下载

0 0
原创粉丝点击