android Custom view Ninth Palace Unlocking

Keywords: Android github REST less

android Custom view Ninth Palace Unlocking

See the source code for more details.
https://github.com/que123567/lockview

  • 1. Define a class as a grid of nine palaces

    Contains coordinates and indexes (used to record passwords)
    point contains three states corresponding to three different picture styles of points in different situations

package lockview;

/**
 * Created by smaug on 2017/5/11.
 */

public class Point {
    public float x;
    public float y;
    private int index;

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public static final int STATU_NORNAL = 0;
    public static final int STATU_PRESSED = 1;
    public static final int STATU_ERROR = 2;
    public int state;


    public void setState(int state) {
        this.state = state;
    }

    public int getState() {
        return state;
    }

    public Point() {super();}

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }
}
  • 2. New class LockView inherits from View
    Override onDraw() method
    • Initialization points are compared to determine whether the current state is horizontal or vertical based on the width and height of the current screen.
    • Get Bitmap from the resource and set the point to an image.
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
            initPoints();
            initPaint();    
    }

  private void drawPoints(Canvas canvas) {
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                Point point = points[i][j];
                if (point.getState() == Point.STATU_NORNAL) {
                    //Get the coordinates of the current point, subtract the radius of the image and get the coordinate points of left and top.
                    canvas.drawBitmap(point_normal, point.x - br, point.y - br, null);
                } else if (point.getState() == Point.STATU_PRESSED) {
                    canvas.drawBitmap(point_pressed, point.x - br, point.y - br, null);

                } else if (point.getState() == Point.STATU_ERROR) {
                    canvas.drawBitmap(point_error, point.x - br, point.y - br, null);
                }
            }
        }
    }

public class LockView extends View {

 private void initPoints() {
        width = getWidth();
        height = getHeight();
        if (height > width) {//Vertical screen
            offsetY = (height - width) / 2;
            height = width;
        } else { //Horizontal screen
            offsetX = (height - width) / 2;
            width = height;
        }

        /**
         *     Define the coordinates of nine points
         */
        points = new Point[row][colun];
        int index = 1;
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < colun; j++) {
                points[i][j] = new Point(offsetX + (width / (row + 1)) * (i + 1), offsetY +
                        (width / (colun + 1)) * (j + 1));
                points[i][j].setIndex(index);
                index++;
            }
        }

        /**
         * Getting Bitmap from Resources
         */
        point_normal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
        point_pressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
        point_error = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);

        br = point_normal.getWidth() / 2;
    }
}

The results are shown as follows

  • 3. Rewrite onTouchEvent
  case MotionEvent.ACTION_DOWN:
                reset();//The state of the drawing before clearing
                checkedPoint = checkPoint(eventX, eventY, br);
                if (checkedPoint != null) {
                    isSelecte = true;
                    checkedPoint.setState(Point.STATU_PRESSED);
                }
                break;

checkPoint() determines whether the current finger coordinates are on the point picture by calculating the coordinate distance

  private Point checkPoint(float eventX, float eventY, float br) {
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                Point point = points[i][j];
                double distance = getDistance(point.x, point.y, eventX, eventY);
                if (distance < br) {
                    return point;
                }
            }
        }
        return null;
    }

getDistance() Calculates coordinate distance by Pythagorean theorem

private double getDistance(float x, float y, float eventX, float eventY) {
        return Math.sqrt(Math.abs(x - eventX) * Math.abs(x - eventX) + Math.abs(y - eventY) *
                Math.abs(y - eventY));
    }

At this point, the finger touches a certain point, the state of a point will be changed from normal to pressed, and the corresponding pictures will also be changed.

  • 4. Lines between Adding Points and Points
    List --> pointList that defines a Point class in LockView to record points pressed by users

  • When the pointList is empty, that is, when the user does not press any point, the line segment is not drawn, and the rest of the time is drawn.

  • Drawing line segment calls drawLine() method of canvas and passes in starting point x,y coordinate and target point x,y coordinate and a custom paint brush to draw line segment.

 private void drawLine(Canvas canvas) {
        if (pointList.size() > 0) {
            Point a = pointList.get(0);
            for (int i = 1; i < pointList.size(); i++) {
                Point b = pointList.get(i);
                canvas.drawLine(a.x, a.y, b.x, b.y, paint);
                a = b;
            }
            if (!moveOnPoint) { //
                canvas.drawLine(a.x, a.y, eventX, eventY, paint);
            }
        }
    }

The effect is shown in the figure.

  • 5. Automatic connection of intermediate points

In the nine palaces, if the user skips the middle point and connects only the head and the tail, the middle point should be connected automatically according to the rules.

That is to say, in the process of ACTION_MOVE, it is always judged whether the intermediate point is connected, and the judgement of the intermediate point is based on the coordinates of the first and last points/2.

case MotionEvent.ACTION_MOVE:
    if (isSelecte) {
       checkedPoint = checkPoint(eventX, eventY, br);
        if (checkedPoint != null) {
             if (!pointList.contains(checkedPoint)) {
                   middlePoint = checkPoint((checkedPoint.x + lastPoint.x) / 2, (checkedPoint.y + lastPoint.y) / 2, br);
     if (middlePoint != null) {
                middlePoint.setState(Point.STATU_PRESSED);
                        }
                 }
            checkedPoint.setState(Point.STATU_PRESSED);
              moveOnPoint = true;
           } else {
            moveOnPoint = false;
        }
       }
     break;
  • 6. In addition, the password will be recorded during the drawing process, and setOnLockSuccessed monitoring can be set to judge when using the LocKiew, which has parameters: the correct password-passward.

    Correspondingly, if the number of connections is less than 5, the connection fails, and there are also corresponding listening events.

 if (pointList != null) {
                if (pointList.size() == 1) {
                    reset();//Reset
                } else if (pointList.size() < 5) {//Insufficient number
                    errorPoint();//Drawing the wrong pattern
                    if (onLockChangeListener != null) { //fail
                        onLockChangeListener.setOnLockError();
                    }
                } else if (pointList.size() >= 5) { //The number of links in nine palaces should be greater than or equal to 5.
                    StringBuilder passward = new StringBuilder();
                    for (int i = 0; i < pointList.size(); i++) {
                        int tmpIndex = pointList.get(i).getIndex();
                        passward.append(tmpIndex + "");
                    }
                    if (onLockChangeListener != null)//Success
                        onLockChangeListener.setOnLockSuccessed(passward);
                }
            }

Author: Qiu Zhonghao: Original address

Posted by rweston002 on Tue, 25 Jun 2019 16:54:13 -0700