Android 圖案解鎖 9宮格密碼解鎖

序言  第一次寫Android技術博客,不知道該如何下手。

背景  現在人們越來越重視自己的隱私,對於一些涉及用戶隱私的應用,用戶可能會希望在應用啓動時必須先輸入密碼。傳統的數字式密碼記憶繁瑣、容易破解,而圖案解鎖則可以解決這個問題。因此,在應用中添加圖案解鎖功能,可以提高應用的可靠性,獲得用戶的信任。 


今天,我要介紹的是Android 的屏幕9宮格圖形解鎖,如果有什麼不對的地方,望各位批評指正。直接上代碼


1. 首先自定義圖形密碼控件,繼承自View,創建並繪製9個點,並重寫onTouchEvent方法。


public class GestureLock extends View {


    private Point[][] points = new Point[3][3];
    private boolean inited = false;


    private boolean isDraw = false;
    private ArrayList<Point> pointList = new ArrayList<Point>();
    private ArrayList<Integer> passList = new ArrayList<Integer>();


    private Bitmap bitmapPointError;
    private Bitmap bitmapPointNormal;
    private Bitmap bitmapPointPress;


    private OnDrawFinishedListener listener;


    float mouseX, mouseY;


    private float bitmapR;


    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Paint pressPaint = new Paint();
    Paint errorPaint = new Paint();


    public GestureLock(Context context) {
        super(context);
    }


    public GestureLock(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public GestureLock(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mouseX = event.getX();
        mouseY = event.getY();
        int[] ij;
        int i, j;
        switch (event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                resetPoints();
                ij = getSelectedPoint();
                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 = getSelectedPoint();
                    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 (listener != null && isDraw)
                {
                    valid = listener.OnDrawFinished(passList);
                }
                if (!valid)
                {
                    for (Point p : pointList)
                    {
                        p.state = Point.STATE_ERROR;
                    }
                }
                isDraw = false;
                break;
        }
        this.postInvalidate();
        return true;
    }


    private int[] getSelectedPoint()
    {
        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) < bitmapR)
                {
                    int[] result = new int[2];
                    result[0] = i;
                    result[1] = j;
                    return result;
                }
            }
        }
        return null;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        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 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);
        }
    }


    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)
                {
                    //Normal
                    canvas.drawBitmap(bitmapPointNormal, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);
                }
                else if (points[i][j].state == Point.STATE_PRESS)
                {
                    //Press
                    canvas.drawBitmap(bitmapPointPress, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);


                }
                else {
                    //ERROR
                    canvas.drawBitmap(bitmapPointError, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);


                }
            }
        }
    }


    private void init()
    {
        pressPaint.setColor(Color.YELLOW);
        pressPaint.setStrokeWidth(5);
        errorPaint.setColor(Color.RED);
        errorPaint.setStrokeWidth(5);


        bitmapPointError = BitmapFactory.decodeResource(getResources(), R.mipmap.error);
        bitmapPointNormal = BitmapFactory.decodeResource(getResources(), R.mipmap.normal);
        bitmapPointPress = BitmapFactory.decodeResource(getResources(), R.mipmap.press);


        bitmapR = bitmapPointError.getHeight() / 2;
        int width = getWidth();
        int height = getHeight();
        int offset = Math.abs(width - height) / 2;
        int offsetX, offsetY;
        int space;
        if(width > height)
        {
            space = height / 4;
            offsetX = offset;
            offsetY = 0;
        }
        else
        {
            space = width / 4;
            offsetX = 0;
            offsetY = offset;
        }
        points[0][0] = new Point(offsetX + space, offsetY + space);
        points[0][1] = new Point(offsetX + space * 2, offsetY + space);
        points[0][2] = new Point(offsetX + space * 3, offsetY + space);


        points[1][0] = new Point(offsetX + space, offsetY + space * 2);
        points[1][1] = new Point(offsetX + space * 2, offsetY + space * 2);
        points[1][2] = new Point(offsetX + space * 3, offsetY + space * 2);


        points[2][0] = new Point(offsetX + space, offsetY + space * 3);
        points[2][1] = new Point(offsetX + space * 2, offsetY + space * 3);
        points[2][2] = new Point(offsetX + space * 3, offsetY + space * 3);


        inited = true;
    }


    public void resetPoints()
    {
        passList.clear();
        pointList.clear();
        for (int i = 0; i < points.length; i++)
        {
            for (int j = 0; j < points[i].length; j++)
            {
                points[i][j].state = Point.STATE_NORMAL;
            }
        }
        this.postInvalidate();
    }


    public interface OnDrawFinishedListener
    {
        boolean OnDrawFinished(List<Integer> passList);
    }


    public void setOnDrawFinishedListener(OnDrawFinishedListener listener)
    {
        this.listener = listener;
    }
}

輔助類 Point.java

public class Point {
    public static int STATE_NORMAL = 0;
    public static int STATE_PRESS = 1;
    public static int STATE_ERROR = 2;


    float x;
    float 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;
    }


}


2.MainActivity.java  設置和檢驗密碼鎖。

public class MainActivity extends ActionBarActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        Button btn_setting = (Button)findViewById(R.id.button);
        Button btn_lock = (Button)findViewById(R.id.button2);


        btn_setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SettingActivity.class);
                startActivity(intent);
            }
        });


        btn_lock.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, LockActivity.class);
                startActivity(intent);
            }
        });


    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();


        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }


        return super.onOptionsItemSelected(item);
    }
}


大體核心代碼就是這些,後面有demo鏈接,可根據需要自行下載。



Demo源碼下載




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