Easy implementation of Android (Android) nine Sudoku unlock _android

Source: Internet
Author: User
Tags gety pow touch

Effect chart

Ideas

First, let's analyze the idea of realizing the nine Sudoku: When the user's finger touches a certain point, to determine whether the point is within a certain range of nine Sudoku, if within the range, then the lattice into a selected state; After the user's fingers slide, the center of the grid is centered, the user's finger for the end, two-point connection. Finally, when the user's finger is raised, judge whether the nine Sudoku password matches the original password.

The general idea of the flow is the above, we can come to practice the following.

Point class

Let's start by creating a point class that represents the nine squares of the nine-Sudoku lock. In addition to coordinates x, Y, there are three modes: Normal mode , press mode , and error mode . Depending on the pattern, the color of the grid varies, which is explained in the following.

public class Point {

 private float x;
 private float y;
 Normal mode public
 static final int normal_mode = 1;
 Press mode public
 static final int pressed_mode = 2;
 Error mode public
 static final int error_mode = 3;
 private int state = Normal_mode;
 Represents the password for the grid, such as "1", "2", and other
 private String mark;

 Public String Getmark () {return
  mark;
 }

 public void Setmark (String mark) {
  This.mark = mark;
 }

 Public point (float x, float y, String Mark) {
  this.x = x;
  This.y = y;
  This.mark = Mark;

 public int getState () {return state
  ;
 }

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

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

}

Rotatedegrees class

With the above point class, we also create a rotatedegrees class, which is to compute the angle between the two points coordinates :

The public class Rotatedegrees {/** * calculates the angle between them based on the incoming point * @param a * @param b * @return/public static Flo
  At Getdegrees (Point A, point B) {float degrees = 0;
  float AX = A.getx ();
  float AY = a.gety ();
  float BX = B.getx ();

  float by = b.gety ();
   if (AX = = BX) {if (AY < by) {degrees = 90;
   else {degrees = 270;
   ' Else if ' (by = = AY) {if (AX < BX) {degrees = 0;
   else {degrees = 180;  } else {if (AX > BX) {if (AY > by) {//third quadrant degrees = 180 + (float) (Math.atan2 (ay-by, AX-BX)
    * 180/math.pi);
    else {//second quadrant degrees = 180-(float) (Math.atan2 (By-ay, AX-BX) * 180/math.pi);
    } else {if (AY > by) {//Fourth quadrant degrees = 360-(float) (Math.atan2 (ay-by, Bx-ax) * 180/math.pi);
    else {//First quadrant degrees = (float) (Math.atan2 (By-ay, Bx-ax) * 180/math.pi);
 }} return degrees;
 /** * Calculates the angle between them based on point and (x,y) * @param a * @param BX * @param by * @return/public static float getdegrees (point A, float BX, float by) {Point B = new
  Point (BX, by, NULL);
 Return Getdegrees (A, b); }

}

Screenlockview class

Then we have to prepare a few pictures of nine Sudoku, such as in the nine Sudoku of the lattice, the NORMAL_MODE pattern is blue, when the fingers hold the nine Sudoku lattice is green, which corresponds to the above Point class in the PRESSED_MODE pattern, and the ERROR_MODE pattern is red. There are also links between the dots, depending on the pattern and different colors. I'm not going to post the pictures here.

With the image resource, all we have to do is load the picture in the constructor first:

public class Screenlockview extends View {private static final String TAG = "Screenlockview";
 Picture of the wrong lattice private Bitmap errorbitmap;
 Picture of the normal lattice private Bitmap normalbitmap;
 Finger pressed when the picture of the lattice private Bitmap pressedbitmap;
 The picture of the connection when wrong private Bitmap lineerrorbitmap;
 Finger hold when the picture of the attachment private Bitmap linepressedbitmap;
 Offset, so that nine Sudoku in the center of the screen private int offset;
 Whether the nine squares of nine Sudoku have already initialized private Boolean init;
 Lattice radius private int radius;
 Password private String password = "123456";
 Nine lattice private point[][] points = new point[3][3];
 private int width;
 private int height;
 Private Matrix matrix = new Matrix ();
 Private float MoveX =-1;
 Private float Movey =-1;
 Whether the finger in the mobile private Boolean ismove;
 Whether can touch, when the user lifts the finger, delimits nine sudoku The password is not correct when cannot touch the private Boolean Istouch = true;
 Used to store the point where the record was pressed private list<point> pressedpoint = new arraylist<> ();

 Screen unlock listener private onscreenlocklistener listener;
 Public Screenlockview {This (context, NULL); } public ScreenlockviEW (context, AttributeSet attrs) {This (context, attrs, 0);
  Public Screenlockview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr);
  Errorbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.bitmap_error);
  Normalbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.bitmap_normal);
  Pressedbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.bitmap_pressed);
  Lineerrorbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.line_error);
  Linepressedbitmap = Bitmapfactory.decoderesource (Getresources (), r.drawable.line_pressed);
 Radius = Normalbitmap.getwidth ()/2; }
 ...
}

In the constructor we basically load the picture and get the lattice radius, which is half the width of the picture.

And then we'll look at the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method:

@Override
protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
 int widthsize = Measurespec.getsize (WIDTHMEASURESPEC);
 int widthmode = Measurespec.getmode (widthmeasurespec);
 int heightsize = measurespec.getsize (heightmeasurespec);
 int heightmode = Measurespec.getmode (heightmeasurespec);
 if (Widthsize > Heightsize) {
  offset = (widthsize-heightsize)/2;
 } else {
  offset = (heightsize-width Size)/2;
 }
 Setmeasureddimension (Widthsize, heightsize);
}

In the onMeasure(int widthMeasureSpec, int heightMeasureSpec) method, the corresponding offset is mainly obtained so that the onDraw(Canvas canvas) nine Sudoku are plotted in the center of the screen below.

Here's onDraw(Canvas canvas) how:

@Override
protected void OnDraw (Canvas Canvas) {
 if (!init) {
  width = getwidth ();
  Height = getheight ();
  Initpoint ();
  init = true;
 }
 Draw Nine Sudoku lattice
 drawpoint (canvas);

 if (MoveX!=-1 && movey!=-1) {
  //Draw Straight line
  drawLine (canvas);
 }
}

First, it determines whether the method is invoked for the first time onDraw(Canvas canvas) , and initializes the points for the first time:

Initialize dot
private void Initpoint () {
 points[0][0] = new Point (WIDTH/4, offset + WIDTH/4, "0");
 POINTS[0][1] = new Point (WIDTH/2, offset + WIDTH/4, "1");
 POINTS[0][2] = new Point (Width * 3/4, offset + WIDTH/4, "2");

 Points[1][0] = new Point (WIDTH/4, offset + WIDTH/2, "3");
 POINTS[1][1] = new Point (WIDTH/2, offset + WIDTH/2, "4");
 POINTS[1][2] = new Point (Width * 3/4, offset + WIDTH/2, "5");

 Points[2][0] = new Point (WIDTH/4, offset + width * 3/4, "6");
 POINTS[2][1] = new Point (WIDTH/2, offset + width * 3/4, "7");
 POINTS[2][2] = new Point (Width * 3/4, offset + width * 3/4, "8");
}

In the initPoint() method, nine squares are created and the corresponding location and password are set. The init is set to false after initialization is completed, and will not be called again next time.

Go back and look at the onDraw(Canvas canvas) other logic, and then call drawPoint(canvas) to draw the lattice:

Draw Nine Sudoku lattice
private void Drawpoint (Canvas Canvas) {for
 (int i = 0; i < points.length; i++) {for
  (int j = 0 ; J < Points[i].length; J + +) {
   int state = Points[i][j].getstate ();
   if (state = = Point.normal_mode) {
    canvas.drawbitmap (Normalbitmap, Points[i][j].getx ()-Radius, points[i][j].gety ( )-radius, null;
   else if (state = = Point.pressed_mode) {
    canvas.drawbitmap (Pressedbitmap, Points[i][j].getx ()-radius, points[i][j] . GetY ()-radius, null);
   else {
    Canvas.drawbitmap (Errorbitmap, Points[i][j].getx ()-Radius, points[i][j].gety ()-radius, null);
  }
 }
}

In the drawing of the lattice is still very simple, mainly divided into three kinds: the normal mode of the lattice , under the mode of the lattice and the wrong mode of the lattice .

Ontouchevent

After the grid is drawn, we don't look at the final drawLine(canvas) method, because drawing the line is related to the touch event of the user's finger, so we turn our eyes to the onTouchEvent(MotionEvent event) method:

@Override public boolean ontouchevent (Motionevent event) {if (Istouch) {float x = Event.getx ();
  Float y = event.gety ();
  Point Point;
    Switch (event.getaction ()) {case Motionevent.action_down://Determine whether the user touches the point within any of the nine Sudoku points = Ispoint (x, y); 
    if (point!= null) {point.setstate (Point.pressed_mode);//toggle to pressed mode Pressedpoint.add (point);
   } break;
     Case MotionEvent.ACTION_MOVE:if (pressedpoint.size () > 0) {point = Ispoint (x, y);
       if (point!= null) {if (!crosspoint) {point.setstate (Point.pressed_mode);
      Pressedpoint.add (point);
     } MoveX = x;
     Movey = y;
    Ismove = true;
   } break;
    Case MotionEvent.ACTION_UP:isMove = false;
    String temppwd = "";
    for (point P:pressedpoint) {temppwd + = P.getmark ();
    } if (listener!= null) {Listener.getstringpassword (TEMPPWD); } if (temppwd.equals (password)) {if (listener!= null) {LIstener.ispassword (TRUE);
     } else {for (point p:pressedpoint) {p.setstate (Point.error_mode);
     } Istouch = false;
     This.postdelayed (runnable, 1000);
     if (listener!= null) {Listener.ispassword (false);
  }} break;
 } invalidate ();
return true;
 Public interface Onscreenlocklistener {public void Getstringpassword (String password);
public void Ispassword (Boolean flag); public void Setonscreenlocklistener (Onscreenlocklistener listener) {This.listener = listener;}

In MotionEvent.ACTION_DOWN , the method is isPoint(float x, float y) used to determine whether the coordinate point of the user's touch event is within any of the nine Sudoku. If so, you need to add the nine Sudoku to the pressedPoint :

Whether the touch point is a lattice
private points ispoint (float x, float y) {point
 ;
 for (int i = 0; i < points.length. i++) {for
  (int j = 0; J < Points[i].length; J +) {point
   = points[i][j];
   if (Iscontain (point, X, y)) {return point
    ;
   }
 }} return null;
}

Whether the point (X,y) is contained in the
private Boolean iscontain (points point, float x, float y) {
 ///The distance between the points (X,y) and the grid center is contained if less than the radius Return
 math.sqrt (Math.pow (X-point.getx (), 2f) + Math.pow (y-point.gety (), 2f)) <= radius;
}

The next step is to see MotionEvent.ACTION_MOVE the logic. At first it was judged whether the point of the user's touch was a lattice of nine Sudoku. But MotionEvent.ACTION_DOWN there's one more step: If a user touches a grid, it's also about whether the grid is contained pressedPoint inside.

Whether the lattice has been included in the Pressedpoint
private Boolean crosspoint (Point point) {
 if (pressedpoint.contains) { return
  true;
 }
 return false;
}

Finally, to see MotionEvent.ACTION_UP , the stored in pressedPoint the lattice after the user to draw the password, and then set the password compared to the same, if the same callback OnScreenLockListene R listener; the difference is to pressedPoint set all the grid mode in error mode and runnable call reset() Empty pressedPoint , redraw the view, and then callback the listener.

Private Runnable Runnable = new Runnable () {
 @Override public
 void Run () {
  Istouch = true;
  Reset ();
  Invalidate ();
 }
;

Reset grid
private void Reset () {for
 (int i = 0; i < points.length; i++) {for
  (int j = 0; J < Points[i] . length; J + +) {
   points[i][j].setstate (point.normal_mode);
  }
 }
 Pressedpoint.clear ();
}

Now let's look back at the drawLine (Canvas Canvas) method before OnDraw (Canvas Canvas) :

Draw straight line private void DrawLine (Canvas Canvas) {//all squares in pressedpoint are traversed sequentially for (int i = 0; i < pressedpoint.size ()-1;
  i++) {//Get the current grid point point = Pressedpoint.get (i);
  Get the next lattice point nextpoint = Pressedpoint.get (i + 1);

  Rotate Canvas canvas.rotate (rotatedegrees.getdegrees (Point, Nextpoint), Point.getx (), point.gety ());
  Matrix.reset ();
  Set the length of the stretch according to the distance Matrix.setscale (getdistance (Point, Nextpoint)/Linepressedbitmap.getwidth (), 1f);


  Perform translational Matrix.posttranslate (Point.getx (), point.gety ()-Linepressedbitmap.getwidth ()/2);
  if (point.getstate () = = Point.pressed_mode) {canvas.drawbitmap (linepressedbitmap, matrix, NULL);
  else {canvas.drawbitmap (lineerrorbitmap, matrix, NULL);
 //Rotate the canvas back to Canvas.rotate (-rotatedegrees.getdegrees (Point, Nextpoint), Point.getx (), point.gety ());
  //If the finger is moving in the case if (ismove) {Point lastpoint = Pressedpoint.get (Pressedpoint.size ()-1); Canvas.rotate (Rotatedegrees.getdegrees (Lastpoint, MoveX, Movey), Lastpoint.getx (), lastpoint.gety ());
  Matrix.reset ();
  LOG.I (TAG, "the Distance:" + getdistance (Lastpoint, MoveX, Movey)/Linepressedbitmap.getwidth ());
  Matrix.setscale (Getdistance (Lastpoint, MoveX, Movey)/Linepressedbitmap.getwidth (), 1f);
  Matrix.posttranslate (Lastpoint.getx (), lastpoint.gety ()-Linepressedbitmap.getwidth ()/2);

  Canvas.drawbitmap (linepressedbitmap, matrix, NULL);
 Canvas.rotate (-rotatedegrees.getdegrees (Lastpoint, MoveX, Movey), Lastpoint.getx (), lastpoint.gety ()); }///According to point and coordinate points to calculate the distance between private float getdistance (dot point, float moveX, float movey) {point b = new Point (MoveX,
 Movey,null);
Return getdistance (POINT,B); ///Based on two point calculates the distance between private float getdistance (Point point, point Nextpoint) {return (float) math.sqrt (Math.pow nextp
Oint.getx ()-Point.getx (), 2f) + Math.pow (nextpoint.gety ()-point.gety (), 2f)); }

drawLine(Canvas canvas) The logic of the whole is not complex, first of pressedPoint all the grid in order to traverse, connect them. After that, if the user's fingers are still sliding, connect the last grid with the user's finger.

Summarize

Screenlockview in the code is almost these, realize the effect is not bad, of course, you can set your own favorite nine Sudoku Pictures, as long as the replacement can be. If you have questions about this article, you can leave a message. Hopefully this article will help you develop Android.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.