android图案解锁功能的实现

来源:互联网 发布:苹果电脑软件如何升级 编辑:程序博客网 时间:2024/04/29 21:37

我们经常会在app中看到图案解锁的功能,所以寻思做一个,在某客视频上看到了教程,自己跟着做了一遍,记录一下,顺便理清一下思路。

思路讲解:

首先自定义一个图案的view,其中实现onDraw方法,以及添加接口回调进行验证密码正确性。
自定义view效果如下:
这里写图片描述

首先新建一个记录点的坐标的一个bean

public class Point {    //表示图案状态    public static  int STATE_NORMAL=0;    public static  int STATE_PRESS=1;    public static  int STATE_ERROR=2;    //坐标    float x,y;    int state=STATE_NORMAL;    public Point(float x, float y) {        this.x = x;        this.y = y;    }    //判断按下屏幕的点是否在某一个圆圈的区域内    public  float distance(Point a)    {        float distance= (float) Math.sqrt((x-a.x)*(x-a.x)+(y-a.y)*(y-a.y));        return  distance;    }}

下面是自定义view代码:

public class GestureLockView extends View {    //三张不同状态圆的图片    private Bitmap error,normal,press;    //    private ArrayList<Point> pointlist=new ArrayList<>();    //设置圆的坐标位置的数组    private  Point[][] points=new Point[3][3];    //画圆的画笔(后面的参数为抗锯齿的作用)    private Paint  paint=new Paint(Paint.ANTI_ALIAS_FLAG);    //设置回调监听事件    private OnDrawFinsihListner listner;    //保存圆的半径    private float radius;    public GestureLockView(Context context) {        super(context);    }    public GestureLockView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public GestureLockView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    //判断是否初始化    private boolean inited=false;    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //ondraw方法会多次调用所以要设置标记位判断是否调用过        if (!inited){            init();        }        //画图        drawPoints(canvas);        //画线        if (pointlist.size()>0)        {   //冲重第一个点画起            Point a=pointlist.get(0);            for (int i=1;i<pointlist.size();i++)            {                Point b=pointlist.get(i);                drawLine(canvas,a,b);                a=b;            }            if (isDraw)            {                drawLine(canvas,a,new Point(mouseX,mouseY));            }        }    }    //绘制圆圈背景图案    private  void drawPoints(Canvas canvas){        for (int i=0;i<points.length;i++ )        {            for (int j=0;j<points[i].length;j++)            {                if (points[i][j].state==Point.STATE_NORMAL)                {                    //正常状态                    canvas.drawBitmap(normal,points[i][j].x-radius,points[i][j].y-radius,paint);                }                else  if (points[i][j].state==Point.STATE_PRESS)                {                    //按下状态                    canvas.drawBitmap(press,points[i][j].x-radius,points[i][j].y-radius,paint);                }else                {                    //错误状态                    canvas.drawBitmap(error,points[i][j].x-radius,points[i][j].y-radius,paint);                }            }        }    }    //初始化    private  void init(){        pressPaint.setColor(Color.BLUE);        //画笔宽度        pressPaint.setStrokeWidth(5);        errorPaint.setColor(Color.RED);        errorPaint.setStrokeWidth(5);        //获取图片        error= BitmapFactory.decodeResource(getResources(),R.drawable.error);        press=BitmapFactory.decodeResource(getResources(),R.drawable.press);        normal=BitmapFactory.decodeResource(getResources(),R.drawable.normal);        radius=error.getHeight()/2;        int width=getWidth();        Log.e("width",width+"");        int height=getHeight();        Log.e("height",height+"");        //显示位置的偏移量        int offset=Math.abs(width-height)/2;        //图案偏移量        int offsetX,offsetY;        //小方格偏移量        int space;        //判断横屏还是竖屏        if (width>height){            offsetX=offset;            offsetY=0;            space=height/4;        }        else {            space=width/4;            offsetX=0;            offsetY=offset;        }        //绘制圆圈        for (int i=0;i<3;i++)        {            for (int j=0;j<3;j++){                points[i][j]=new Point(offsetX+space*(j+1),offsetY+space*(i+1));            }        }        inited=true;    }    //获取触摸的点    private  float mouseX,mouseY;    //是否在绘制状态    private  boolean isDraw=false;    //触摸事件    @Override    public boolean onTouchEvent(MotionEvent event)    {        //得到按下坐标        mouseX=event.getX();        mouseY=event.getY();        int[] ij;        int i,j;        switch (event.getAction())        {            case MotionEvent.ACTION_DOWN:                //清空绘制过程                resetPoint();                ij=getSelectionPoint();                if (ij!=null)                {                    isDraw=true;                     i=ij[0];                     j=ij[1];                    points[i][j].state=Point.STATE_PRESS;                    pointlist.add(points[i][j]);                    passlist.add(i*3+j);                }                break;            case MotionEvent.ACTION_MOVE:                if (isDraw)                {                     ij=getSelectionPoint();                    if (ij!=null)                    {                         i=ij[0];                         j=ij[1];                        if (!pointlist.contains(points[i][j]))                        {                            points[i][j].state=Point.STATE_PRESS;                            pointlist.add(points[i][j]);                            passlist.add(i*3+j);                        }                    }                }                break;            case MotionEvent.ACTION_UP:                boolean valid=false;                if (listner!=null&&isDraw)                {                    valid=listner.OnDrawFinished(passlist);                }                if (!valid)                {                    for (Point point:pointlist)                        point.state=Point.STATE_ERROR;                }                isDraw=false;                break;        }        this.postInvalidate();        return true;    }    //当手指按下,判断属于那个圆圈    private int[] getSelectionPoint()    {        Point pMouse=new Point(mouseX,mouseY);        for (int i=0;i<points.length;i++){            for (int j=0;j<points[i].length;j++)            {                if (points[i][j].distance(pMouse)<radius)                {                    int[] result=new int[2];                    result[0]=i;                    result[1]=j;                    return result;                }            }        }        return  null;    }    private Paint errorPaint=new Paint();    private Paint pressPaint=new Paint();    private  void drawLine(Canvas canvas,Point a,Point b)    {        if (a.state==Point.STATE_PRESS)        {            canvas.drawLine(a.x,a.y,b.x,b.y,pressPaint);        }        else if (a.state==Point.STATE_ERROR){            canvas.drawLine(a.x,a.y,b.x,b.y,errorPaint);        }    }    public  void  resetPoint(){        pointlist.clear();        passlist.clear();        for (int i=0;i<points.length;i++)        {            for (int k=0;k<points[i].length;k++)                points[i][k].state=Point.STATE_NORMAL;        }        this.postInvalidate();    }    private  ArrayList<Integer> passlist=new ArrayList<>();    public interface OnDrawFinsihListner    {        boolean OnDrawFinished(List<Integer> passlist);    }    public  void setOnDrawFinishedListener(OnDrawFinsihListner listener)    {        this.listner=listener;    }}

主页面布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:orientation="vertical"    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="设置图案密码"        android:id="@+id/button"        android:layout_gravity="center_horizontal" />    <Button        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="测试图案密码"        android:id="@+id/button2"        android:layout_gravity="center_horizontal" /></LinearLayout>

主页面代码:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent(MainActivity.this, SettingAct.class);                startActivity(intent);            }        });        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent=new Intent(MainActivity.this,LockAct.class);                startActivity(intent);            }        });    }}

设置页面代码:

public class SettingAct extends AppCompatActivity  {    private GestureLockView lockView;    private List<Integer> passlist;    @Override    protected void onCreate(final Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_setting);        lockView= (GestureLockView) findViewById(R.id.view);        findViewById(R.id.btn_reset).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                lockView.resetPoint();            }        });        findViewById(R.id.btn_save).setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (passlist!=null)                {                    StringBuilder sb=new StringBuilder();                    for (Integer i:passlist)                    {                        sb.append(i);                    }                    SharedPreferences sharedPreferences=SettingAct.this.getSharedPreferences("password", Context.MODE_PRIVATE);                    SharedPreferences.Editor editor=sharedPreferences.edit();                    editor.putString("password", sb.toString());                    editor.commit();                    Toast.makeText(SettingAct.this,"保存完成",Toast.LENGTH_SHORT).show();                    Intent intent=new Intent(SettingAct.this,MainActivity.class);                    startActivity(intent);                }            }        });        lockView.setOnDrawFinishedListener(new GestureLockView.OnDrawFinsihListner() {            @Override            public boolean OnDrawFinished(List<Integer> passlist) {                if (passlist.size()<3)                {                    Toast.makeText(SettingAct.this,"密码不能小于三个点",Toast.LENGTH_SHORT).show();                    return  false;                }else                {                    SettingAct.this.passlist=passlist;                    return  true;                }            }        });    }}

测试页面代码:

public class LockAct extends AppCompatActivity {private   String passwaord;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_lock);        GestureLockView gestureLockView= (GestureLockView) findViewById(R.id.view2);        SharedPreferences sharedPreferences=getSharedPreferences("password", Context.MODE_PRIVATE);       passwaord =sharedPreferences.getString("password","");        Log.e("password",passwaord);        gestureLockView.setOnDrawFinishedListener(new GestureLockView.OnDrawFinsihListner() {            @Override            public boolean OnDrawFinished(List<Integer> passlist) {                StringBuilder stringBuilder=new StringBuilder();                for (Integer i:passlist)                {                    stringBuilder.append(i);                }                Log.e("sb",stringBuilder.toString());                if (stringBuilder.toString().equals(passwaord))                {                    Toast.makeText(LockAct.this, "密码正确", Toast.LENGTH_SHORT).show();                    return true;                }                else                {                    Toast.makeText(LockAct.this, "密码错误", Toast.LENGTH_SHORT).show();                    return  false;                }            }        });    }}

最终效果图:
这里写图片描述

注意:
这里很奇怪,为什么布局显示正常的图案,但是在模拟器中圆圈就变大了,然后我发现换为API 15的页面布局中显示出来的就是当前的结果,如果哪位大大知道为什么请告诉我好么!!!!!!!

0 0
原创粉丝点击