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.