Brief introduction
This paper introduces a detailed process of using and implementing the open Source Library of Android gesture cipher, which mainly realizes the following functions:
- Support the drawing of gesture cipher, and support the password save function, when unlocking, it automatically gives the result of the password.
- Encapsulates the method of drawing a password, which is more than two times the same password, you can quickly set the gesture password
- You can set the maximum number of retries after a password entry error
- Can customize the color of the gesture cipher pattern in different states
- Number of touch points that can customize the gesture password (n*n)
Recently need to use the gesture password unlock function, find some demo feel to use up a little trouble, so refer to some articles made their own under the wheel, encapsulating some related methods, the use of more convenient.
GitHub link below, feel can also please help star support ~
GitHub Link Personal Blog
Working with effects
First look at the use of the effect:
How to use
Use this control in an XML layout file
<com.syd.oden.gesturelock.view.gesturelockviewgroup
android:id= "@+id/gesturelock"
android:layout_ Width= "Match_parent"
android:layout_height= "match_parent"
app:preference_id= "1"
android:layout_ margintop= "30DP"
app:count= "3"/>
Some of the parameters that you can set are described below:
- Color_no_finger: The color of the circle when not touched
- COLOR_FINGER_ON: The color of the circle when touching
- Color_finger_up_correct: Enter the correct color of the circle
- Color_finger_up_error: The color of a circle when an error occurs
- Count: Rounded number of passwords, n*n
- PREFERENCE_ID: gesture password saved ID number, do not enter or enter-1 use the default ID
Class
private void Initgesture () {
Mgesturelockviewgroup = (gesturelockviewgroup) Findviewbyid (r.id.gesturelock);
Gestureeventlistener ();
Gesturepasswordsettinglistener ();
Gestureretrylimitlistener ();
}
Set Gesture Password listening events
private void Gestureeventlistener () {Mgesturelockviewgroup.setgestureeventlistener () (
new Gestureeventlistener ()) {
@Override public
void Ongestureevent (Boolean matched) {
mylog.d ("ongestureevent matched:" + matched);
if (!matched) {
tv_state.settextcolor (color.red);
Tv_state.settext ("Gesture password error");
} else {
if (isreset) {
isreset = false;
Toast.maketext (Mainactivity.this, "clear success!", Toast.length_short). Show ();
Resetgesturepattern ();
} else {
tv_state.settextcolor (color.white);
Tv_state.settext ("Gesture password correct");
}
If a password is already set, the callback is entered, where the result is processed, and a reset password is added to the example above.
Gesture Password Settings
private void Gesturepasswordsettinglistener () {
Mgesturelockviewgroup.setgesturepasswordsettinglistener (new Gesturepasswordsettinglistener () {
@Override public
boolean onfirstinputcomplete (int len) {
if (Len > 3 ) {
tv_state.settextcolor (color.white);
Tv_state.settext ("Draw gesture password Again");
return true;
} else {
tv_state.settextcolor (color.red);
Tv_state.settext ("Connect at least 4 points, please re-enter!");
return false;
}
}
@Override public
void onsuccess () {
tv_state.settextcolor (color.white);
Toast.maketext (mainactivity.this, "Password settings successful!", Toast.length_short). Show ();
Tv_state.settext ("Please enter the gesture password unlock!");
}
@Override public
void Onfail () {
tv_state.settextcolor (color.red);
Tv_state.settext ("not consistent with previous drawing, please redraw");}
If the password has not been set, draw gestures will enter the callback, the return value is drawn to the number of touch points, Onfirstinputcomplete return true to enter the second gesture password drawing, two input consistent after the automatic save password.
Retry number exceeded limit listening
private void Gestureretrylimitlistener () {
Mgesturelockviewgroup.setgestureunmatchedexceedlistener (3, new Gestureunmatchedexceedlistener () {
@Override public
void Onunmatchedexceedboundary () {
tv_ State.settextcolor (color.red);
Tv_state.settext ("Too many errors, please try again later!");
}
If the listener event is set, the input error is limited to the number of times the upper limit is exceeded and the callback is processed.
Clear the logic of the password to add a judge to handle it, you can see the GitHub on the demo
Some of the other APIs
public void Removepassword (): Clear password public
void Savepassword (): Save password, set gesture password after successful will automatically save, also can call the interface set password public
void GetPassword (): Get password public
void setretrytimes (int retrytimes): Set the maximum number of retries public
Boolean Issetpassword (): Returns whether the password public
void Resetview () is now set: Reset the View
Import the library in the project
Only two lines of code should be added:
In the build.gradle of the project, add:
allprojects {
repositories {
...
Maven {URL ' Https://jitpack.io '}}}
The build.gradle of module adds dependencies:
dependencies {
compile ' com.github.autume:gesturelock:1.0.0 '
}
The total use is this, is not very simple!
Specific implementation process
The following is a process of implementation that can be skipped if you just use it directly.
A rounded view of a custom gesture password
This part of the main reference Hongyang big blog, slightly modified a bit
Initializing incoming parameters
Public Gesturelockview (context context, int colornofingerr, int colorfingeron, int colorcorrect, int colorerror) {
su per (context);
This.mcolornofinger = Colornofingerr;
This.mcolorfingeron = Colorfingeron;
This.mcolorfingerupcorrect = Colorcorrect;
This.mcolorfingeruperror = Colorerror;
Mpaint = new Paint (paint.anti_alias_flag);
Marrowpath = new Path ();
}
Draw a different color circle according to the different touch states
@Override protected void OnDraw (Canvas Canvas) {switch (mcurrentstatus) {case status_finger_on://Draw Outer Circle
Mpaint.setstyle (Style.stroke);
Mpaint.setcolor (Mcolorfingeron);
Mpaint.setstrokewidth (2);
Canvas.drawcircle (Mcenterx, Mcentery, Mradius, Mpaint);
Draw Inner Circle Mpaint.setstyle (Style.fill);
Canvas.drawcircle (Mcenterx, Mcentery, Mradius * minnercircleradiusrate, Mpaint);
Break
Case STATUS_FINGER_UP://Draw the outer circle if (gesturelockviewgroup.iscorrect) Mpaint.setcolor (mcolorfingerupcorrect);
else Mpaint.setcolor (mcolorfingeruperror);
Mpaint.setstyle (Style.stroke);
Mpaint.setstrokewidth (2);
Canvas.drawcircle (Mcenterx, Mcentery, Mradius, Mpaint);
Draw Inner Circle Mpaint.setstyle (Style.fill);
Canvas.drawcircle (Mcenterx, Mcentery, Mradius * minnercircleradiusrate, Mpaint);
Drawarrow (canvas);
Break
Case Status_no_finger://Draw the Outer Circle Mpaint.setstyle (Style.stroke);
Mpaint.setcolor (Mcolornofinger); CAnvas.drawcircle (Mcenterx, Mcentery, Mradius, Mpaint);
Draw Inner Circle Mpaint.setstyle (Style.fill);
Mpaint.setcolor (Mcolornofinger);
Canvas.drawcircle (Mcenterx, Mcentery, Mradius * minnercircleradiusrate, Mpaint);
Break
}
}
Draw Arrows
@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec, he
IGHTMEASURESPEC);
Mwidth = Measurespec.getsize (Widthmeasurespec);
Mheight = Measurespec.getsize (Heightmeasurespec); Small value in length and width mwidth = mwidth < mheight?
Mwidth:mheight;
Mradius = Mcenterx = Mcentery = MWIDTH/2;
Mradius-= MSTROKEWIDTH/2;
Draws the triangle, initially is a default arrow toward the Isosceles, after the user draws the end, according to the two Gesturelockview to decide how many degrees float marrowlength = MWIDTH/2 * marrowrate;
Marrowpath.moveto (MWIDTH/2, Mstrokewidth + 2);
Marrowpath.lineto (MWIDTH/2-Marrowlength, Mstrokewidth + 2 + marrowlength);
Marrowpath.lineto (MWIDTH/2 + marrowlength, Mstrokewidth + 2 + marrowlength);
Marrowpath.close ();
Marrowpath.setfilltype (Path.FillType.WINDING);
} private void Drawarrow (Canvas Canvas) {if (Marrowdegree!=-1) {Mpaint.setstyle (Paint.Style.FILL);
Canvas.save ();
Canvas.rotate (Marrowdegree, Mcenterx, mcentery); Canvas.drawpath (Marrowpath, Mpaint);
Canvas.restore ();
}
}
ViewGroup of custom gesture passwords
Add Custom View Properties
<?xml version= "1.0" encoding= "Utf-8"?>
<resources> <attr name= "Color_no_finger" format= "
Color "/>
<attr name=" color_finger_on format= "color"/> <attr "name="
format= "Color"/>
<attr name= "color_finger_up_error" format= "color"/> <attr
"Count" format = "integer"/>
<attr name= "preference_id" format= "integer"/>
<declare-styleable "Name=" Gesturelockviewgroup ">
<attr name=" Color_no_finger "/> <attr name=
" color_finger_on "/>
<attr name= "Color_finger_up_correct"/>
<attr name= "Color_finger_up_error"/>
<attr Name= "Count"/>
<attr name= "preference_id"/>
</declare-styleable>
</resources >
Get parameters and Initialize
Public Gesturelockviewgroup (context, AttributeSet attrs, int defstyle) {Super (context, Attrs, Defstyle
); /** * Gets the value of all custom parameters * * TypedArray a = context.obtainstyledattributes (Attrs, R.styleable.gesturelockviewgroup, D
Efstyle, 0);
Mnofingercolor = A.getcolor (R.styleable.gesturelockviewgroup_color_no_finger, Mnofingercolor);
Mfingeroncolor = A.getcolor (r.styleable.gesturelockviewgroup_color_finger_on, Mfingeroncolor); Mfingerupcolorcorrect = A.getcolor (R.styleable.gesturelockviewgroup_color_finger_up_correct,
Mfingerupcolorcorrect);
Mfingerupcolorerror = A.getcolor (R.styleable.gesturelockviewgroup_color_finger_up_error, mFingerUpColorError);
Mcount = A.getint (R.styleable.gesturelockviewgroup_count, Mcount);
Mprferenceid = A.getint (r.styleable.gesturelockviewgroup_preference_id, Mprferenceid);
A.recycle ();
/** * Get Password Status * * gesturepreference = new Gesturepreference (context, Mprferenceid); Password = GESTUREPREFERENCE.READSTRINGPREference ();
LOG.D (TAG, "Password now:" + password); Issetpassword =!password.equals ("null"); Determine if the password has been saved isinpasswordsettingmode =!issetpassword;
When the password is not set, enter the password setting mode//Initialize the brush mpaint = new Paint (Paint.anti_alias_flag);
Mpaint.setstyle (Paint.Style.STROKE);
Mpaint.setstrokecap (Paint.Cap.ROUND);
Mpaint.setstrokejoin (Paint.Join.ROUND);
MPath = new Path ();
}
Draw a circle based on parameters
Call the method after onmeasure to draw the circular matrix
Private gesturelockview[] mgesturelockviews; Save all Gesturelockview private void Initviews () {//Initialize mgesturelockviews if (mgesturelockviews = = null) {Mgestur
Elockviews = new Gesturelockview[mcount * Mcount];
Calculates the width of each gesturelockview mgesturelockviewwidth = (int) (4 * mwidth * 1.0f/(5 * mcount + 1));
Calculates the spacing of each gesturelockview Mmarginbetweenlockview = (int) (Mgesturelockviewwidth * 0.25);
Set the width of the brush to a slightly smaller inner circle diameter of the Gesturelockview mpaint.setstrokewidth (mgesturelockviewwidth * 0.29f); for (int i = 0; i < mgesturelockviews.length i++) {//Initialize each gesturelockview mgesturelockviews[i] = new Gesturel
Ockview (GetContext (), Mnofingercolor, Mfingeroncolor, Mfingerupcolorcorrect, Mfingerupcolorerror);
Mgesturelockviews[i].setid (i + 1); Set the parameters, mainly locating the position between Gesturelockview relativelayout.layoutparams lockerparams = new Relativelayout.layoutparams (mGes
Turelockviewwidth, Mgesturelockviewwidth); is not the first of each row, set the position to the right if (i% mcount!= 0) of the previous one {
Lockerparams.addrule (relativelayout.right_of, Mgesturelockviews[i-1].getid ()); //From the second row, set to the following if (i > MCount-1) {lockerparams.addrule (Relativelayout.below) for view at the same position on the previous line, Mges
Turelockviews[i-mcount].getid ());
//Set the margin int rightMargin = Mmarginbetweenlockview on the lower-right left;
int bottommargin = Mmarginbetweenlockview;
int leftmagin = 0;
int topMargin = 0; /** * Each view has both the right margin and the bottom margin of the first row with the left margin */if (i >= 0 && i < mcount)/The first row {TOPM
Argin = Mmarginbetweenlockview;
} if (i% Mcount = = 0)//The first column {leftmagin = Mmarginbetweenlockview;
} lockerparams.setmargins (Leftmagin, TopMargin, RightMargin, bottommargin);
Mgesturelockviews[i].setmode (Mode.status_no_finger);
AddView (Mgesturelockviews[i], lockerparams);
}
}
}
handles different events in touch listening
@Override public boolean ontouchevent (Motionevent event) {int action = event.getaction ();
int x = (int) event.getx ();
int y = (int) event.gety ();
LOG.D (TAG, "mtrytimes:" + mtrytimes);
The retry count exceeds the limit and returns if (mtrytimes <= 0 && isretrytimelimit) {return true) directly. Switch (action) {case MotionEvent.ACTION_DOWN:reset ();
Reset the break;
Case MotionEvent.ACTION_MOVE:drawAndGetSelectedWhenTouchMove (x, y);
Break Case MotionEvent.ACTION_UP:if (Isinpasswordsettingmode) {if (Gesturepasswordsettinglistener!= null) SETP Asswordhandle ();
Set Password} else {if (mchoose.size () > 0) {iscorrect = Checkanswer ();
else {return true; } if (Gestureeventlistener!= null) {gestureeventlistener.ongestureevent (iscorrect);//To call the result callback} if ( This.mtrytimes = = 0) {gestureunmatchedexceedlistener.onunmatchedexceedboundary ();//Exceeding retry count, enter callback}}
Awwhentouchup (); BreaK
} invalidate ();
return true;
private void Drawandgetselectedwhentouchmove (int x, int y) {mpaint.setcolor (mfingeroncolor);
Mpaint.setalpha (50);
Gesturelockview child = Getchildidbypos (x, y);
if (child!= null) {int cId = Child.getid ();
if (!mchoose.contains (CID)) {mchoose.add (CID);
mchoosestring = mchoosestring + cId;
Child.setmode (mode.status_finger_on);
Set the starting point of the guideline line mlastpathx = Child.getleft ()/2 + child.getright ()/2;
Mlastpathy = Child.gettop ()/2 + child.getbottom ()/2;
if (mchoose.size () = = 1)//is currently added as the first {Mpath.moveto (mlastpathx, mlastpathy);
else//Not the first one, use the line to connect {Mpath.lineto (mlastpathx, mlastpathy);
}}//guide line end mtmptarget.x = x;
Mtmptarget.y = y;
private void Drawwhentouchup () {if (iscorrect) {mpaint.setcolor (mfingerupcolorcorrect);
else {mpaint.setcolor (mfingerupcolorerror);
} mpaint.setalpha (50);
LOG.D (TAG, "mchoose =" + Mchoose); Will eventuallyPoint set position is the starting point, that is, to cancel the guideline line mtmptarget.x = MLASTPATHX;
Mtmptarget.y = Mlastpathy;
Change the state of the child element to up Setitemmodeup ();
Calculates the angle for which the arrows in each element need to be rotated for (int i = 0; i + 1 < mchoose.size (); i++) {int childid = Mchoose.get (i);
int nextchildid = Mchoose.get (i + 1);
Gesturelockview StartChild = (gesturelockview) Findviewbyid (childID);
Gesturelockview nextchild = (gesturelockview) Findviewbyid (Nextchildid);
int dx = Nextchild.getleft ()-Startchild.getleft ();
int dy = nextchild.gettop ()-startchild.gettop ();
Compute angle INT angle = (int) math.todegrees (math.atan2 (dy, dx)) + 90;
Startchild.setarrowdegree (angle);
}
}
Set Password handling:
private void Setpasswordhandle () {
if (iswaitforfirstinput) {
if ( Gesturepasswordsettinglistener.onfirstinputcomplete (Mchoosestring.length ())) {
Firstinputpassword = mchoosestring;
Iswaitforfirstinput = false;
}
} else {
if (firstinputpassword.equals (mchoosestring)) {
gesturepasswordsettinglistener.onsuccess ();
Savepassword (mchoosestring);
Isinpasswordsettingmode = false;
} else {
gesturepasswordsettinglistener.onfail ();
}
}
Reset ();
}
Check the gesture password correctly:
public Boolean checkanswer () {
if (password.equals (mchoosestring)) {return
true;
} else {
if ( Isretrytimelimit)
this.mtrytimes--;
return false;
}
}
Reset:
private void Reset () {
mchoose.clear ();
mchoosestring = "";
Mpath.reset ();
for (Gesturelockview gesturelockview:mgesturelockviews) {
gesturelockview.setmode (mode.status_no_finger);
Gesturelockview.setarrowdegree ( -1);
}
}
Some methods of public disclosure
public void Setgestureeventlistener (Gestureeventlistener gestureeventlistener) {This.gestureeventlistener =
Gestureeventlistener; } public void Setgestureunmatchedexceedlistener (int retrytimes, Gestureunmatchedexceedlistener
Gestureunmatchedexceedlistener) {Isretrytimelimit = true;
This.mtrytimes = Retrytimes;
This.gestureunmatchedexceedlistener = Gestureunmatchedexceedlistener;
} public void Setgesturepasswordsettinglistener (Gesturepasswordsettinglistener gesturepasswordsettinglistener) {
This.gesturepasswordsettinglistener = Gesturepasswordsettinglistener;
public void Removepassword () {gesturepreference.writestringpreference ("null");
This.issetpassword = false;
Iswaitforfirstinput = true;
Isinpasswordsettingmode = true;
} public void Savepassword (String password) {this.password = password;
Gesturepreference.writestringpreference (password);
Public String GetPassword () {return password;
public void Resetview () {reset (); InvalidAte ();
The public void setretrytimes (int retrytimes) {this.mtrytimes = Retrytimes;
public Boolean Issetpassword () {return issetpassword;
}
Defines the preference of the password store
is simply to save and read
Public Gesturepreference (context context, int nametableid) {
This.context = context;
if (Nametableid!=-1)
this.nametable = NameTable + Nametableid;
}
public void Writestringpreference (String data) {
sharedpreferences preferences = Context.getsharedpreferences ( FileName, context.mode_private);
Sharedpreferences.editor Editor = Preferences.edit ();
Editor.putstring (nametable, data);
Editor.commit ();
}
Public String readstringpreference () {
sharedpreferences preferences = context.getsharedpreferences (FileName, Context.mode_private);
Return preferences.getstring (nametable, "null");
}
Summarize
OK, so far, the implementation of the entire gesture password is complete.
The above is a small series of Android to achieve simple gesture password data collation, follow-up to continue to collate relevant information, thank you for your support for this site!