android圖案解鎖功能的實現

我們經常會在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的頁面佈局中顯示出來的就是當前的結果,如果哪位大大知道爲什麼請告訴我好麼!!!!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章