当前位置: 移动技术网 > IT编程>移动开发>Android > Android 仿小米锁屏实现九宫格解锁功能(无需图片资源)

Android 仿小米锁屏实现九宫格解锁功能(无需图片资源)

2019年07月24日  | 移动技术网IT编程  | 我要评论

现在是北京时间几点,长生不老造句,自给自足实验室

 最近公司要求做个九宫格解锁,本人用的是小米手机,看着他那个设置锁屏九宫格很好看,就做了该组件,不使用图片资源,纯代码实现。

尊重每个辛苦的博主,在http://blog.csdn.net/mu399/article/details/38734449的基础上进行修改

效果图:

关键代码类:

mathutil.java

/** 
* @author soban 
* @create 2016/12/5 15:52. 
*/ 
public class mathutil { 
public static double distance(double x1, double y1, double x2, double y2) { 
return math.sqrt(math.abs(x1 - x2) * math.abs(x1 - x2) 
+ math.abs(y1 - y2) * math.abs(y1 - y2)); 
} 
public static double pointtotodegrees(double x, double y) { 
return math.todegrees(math.atan2(x, y)); 
} 
public static boolean checkinround(float sx, float sy, float r, float x, 
float y) { 
return math.sqrt((sx - x) * (sx - x) + (sy - y) * (sy - y)) < r; 
} 
}

point.java

/** 
* @author soban 
* @create 2016/12/5 15:51. 
*/ 
public class point { 
public static int state_normal = 0; 
public static int state_check = 1; // 
public static int state_check_error = 2; // 
public float x; 
public float y; 
public int state = 0; 
public int index = 0;// 
public point() { 
} 
public point(float x, float y, int value) { 
this.x = x; 
this.y = y; 
index = value; 
} 
public int getcolnum() { 
return (index - 1) % 3; 
} 
public int getrownum() { 
return (index - 1) / 3; 
} 
} 

locuspasswordview.java

import android.content.context; 
import android.graphics.canvas; 
import android.graphics.paint; 
import android.graphics.paint.style; 
import android.text.textutils; 
import android.util.attributeset; 
import android.util.log; 
import android.view.motionevent; 
import android.view.view; 
import java.util.arraylist; 
import java.util.list; 
import java.util.timer; 
import java.util.timertask; 
/** 
* @author soban 
* @create 2016/12/5 15:49. 
*/ 
public class locuspasswordview extends view { 
/** 
* 控件的宽高 
*/ 
private float width = 0; 
private float height = 0; 
private boolean iscache = false; //缓存pwdmaxlen个点 
private paint mpaint = new paint(paint.anti_alias_flag); 
private point[][] mpoints = new point[3][3]; 
private float dotradius = 0; 
//选择>pwdminlen的点 
private list<point> spoints = new arraylist<point>(); 
private boolean checking = false; 
private long clear_time = 1000; 
private int pwdmaxlen = 9; 
private int pwdminlen = 4; 
private boolean istouch = true; 
private paint linepaint; 
private paint normalpaint; 
private paint selectedpaint; 
private paint errorpaint; 
private int normaldotcolor = 0xff929292; 
private int selectedcolor = 0xffc3c3c3; 
private int selectedlinecolor = 0xffededed; 
private int errorcolor = 0xfff34b2a; 
private int errorlinecolor = 0xffeebfb6; 
public locuspasswordview(context context, attributeset attrs, int defstyle) { 
super(context, attrs, defstyle); 
} 
public locuspasswordview(context context, attributeset attrs) { 
super(context, attrs); 
} 
public locuspasswordview(context context) { 
super(context); 
} 
@override 
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { 
super.onmeasure(widthmeasurespec, heightmeasurespec); 
int width = measuredimension(200, widthmeasurespec); 
int height = measuredimension(200, heightmeasurespec); 
if (width > height) { 
setmeasureddimension(height, height); 
} else { 
setmeasureddimension(width, width); 
} 
} 
public int measuredimension(int defaultsize, int measurespec) { 
int result; 
int specmode = measurespec.getmode(measurespec); 
int specsize = measurespec.getsize(measurespec); 
if (specmode == measurespec.exactly) { 
result = specsize; 
} else { 
result = defaultsize; //unspecified 
if (specmode == measurespec.at_most) { 
result = math.min(result, specsize); 
} 
} 
return result; 
} 
@override 
public void ondraw(canvas canvas) { 
if (!iscache) { 
initcache(); 
} 
drawtocanvas(canvas); 
} 
private void drawtocanvas(canvas canvas) { 
boolean inerrorstate = false; 
float radiu = dotradius / 16; //圆的半径 
//画点 
for (int i = 0; i < mpoints.length; i++) { 
for (int j = 0; j < mpoints[i].length; j++) { 
point p = mpoints[i][j]; 
if (p.state == point.state_check) { 
selectedpaint.setcolor(selectedcolor); 
canvas.drawcircle(p.x, p.y, radiu, selectedpaint); 
} else if (p.state == point.state_check_error) { 
inerrorstate = true; 
errorpaint.setcolor(errorcolor); 
canvas.drawcircle(p.x, p.y, radiu, errorpaint); 
} else { 
normalpaint.setcolor(normaldotcolor); 
canvas.drawcircle(p.x, p.y, radiu, normalpaint); 
} 
} 
} 
if (inerrorstate) { 
linepaint.setcolor(errorlinecolor); 
} else { 
linepaint.setcolor(selectedlinecolor); 
} 
//画线 
if (spoints.size() > 0) { 
int tmpalpha = mpaint.getalpha(); 
point tp = spoints.get(0); 
for (int i = 1; i < spoints.size(); i++) { 
point p = spoints.get(i); 
drawline(tp, p, canvas, linepaint); 
tp = p; 
} 
if (this.movingnopoint) { 
drawline(tp, new point(moveingx, moveingy, -1), canvas, linepaint); 
} 
mpaint.setalpha(tmpalpha); 
} 
} 
/** 
* 画线 
* @param start 
* @param end 
* @param canvas 
* @param paint 
*/ 
private void drawline(point start, point end, canvas canvas, paint paint) { 
float radiu = dotradius / 16; //圆的半径 
double d = mathutil.distance(start.x, start.y, end.x, end.y); 
float rx = (float) ((end.x - start.x) * radiu / d); 
float ry = (float) ((end.y - start.y) * radiu / d); 
canvas.drawline(start.x + rx, start.y + ry, end.x - rx, end.y - ry, paint); 
} 
/** 
* 缓存控件宽高跟点个位置 
*/ 
private void initcache() { 
width = this.getwidth(); 
height = this.getheight(); 
float x = 0; 
float y = 0; 
if (width > height) { 
x = (width - height) / 2; 
width = height; 
} else { 
y = (height - width) / 2; 
height = width; 
} 
int leftpadding = 15; 
float dotpadding = width / 3 - leftpadding; 
float middlex = width / 2; 
float middley = height / 2; 
mpoints[0][0] = new point(x + middlex - dotpadding, y + middley - dotpadding, 1); 
mpoints[0][1] = new point(x + middlex, y + middley - dotpadding, 2); 
mpoints[0][2] = new point(x + middlex + dotpadding, y + middley - dotpadding, 3); 
mpoints[1][0] = new point(x + middlex - dotpadding, y + middley, 4); 
mpoints[1][1] = new point(x + middlex, y + middley, 5); 
mpoints[1][2] = new point(x + middlex + dotpadding, y + middley, 6); 
mpoints[2][0] = new point(x + middlex - dotpadding, y + middley + dotpadding, 7); 
mpoints[2][1] = new point(x + middlex, y + middley + dotpadding, 8); 
mpoints[2][2] = new point(x + middlex + dotpadding, y + middley + dotpadding, 9); 
log.d("jerome", "canvas width:" + width); 
dotradius = width / 10; 
iscache = true; 
initpaints(); 
} 
private void initpaints() { 
linepaint = new paint(); 
linepaint.setcolor(selectedcolor); 
linepaint.setstyle(style.fill); 
linepaint.setantialias(true); 
linepaint.setstrokewidth(dotradius / 9); 
selectedpaint = new paint(); 
selectedpaint.setstyle(style.fill); 
selectedpaint.setantialias(true); 
selectedpaint.setstrokewidth(dotradius / 6); 
errorpaint = new paint(); 
errorpaint.setstyle(style.fill); 
errorpaint.setantialias(true); 
errorpaint.setstrokewidth(dotradius / 6); 
normalpaint = new paint(); 
normalpaint.setstyle(style.fill); 
normalpaint.setantialias(true); 
normalpaint.setstrokewidth(dotradius / 9); 
} 
/** 
* 检查 
* 
* @param x 
* @param y 
* @return 
*/ 
private point checkselectpoint(float x, float y) { 
for (int i = 0; i < mpoints.length; i++) { 
for (int j = 0; j < mpoints[i].length; j++) { 
point p = mpoints[i][j]; 
if (mathutil.checkinround(p.x, p.y, dotradius, (int) x, (int) y)) { 
return p; 
} 
} 
} 
return null; 
} 
/** 
* 重置 
*/ 
private void reset() { 
for (point p : spoints) { 
p.state = point.state_normal; 
} 
spoints.clear(); 
this.enabletouch(); 
} 
/** 
* 判断点是否有交叉 返回 0,新点 ,1 与上一点重叠 2,与非最后一点重叠 
* 
* @param p 
* @return 
*/ 
private int crosspoint(point p) { 
// 重叠的不最后一个则 reset 
if (spoints.contains(p)) { 
if (spoints.size() > 2) { 
// 与非最后一点重叠 
if (spoints.get(spoints.size() - 1).index != p.index) { 
return 2; 
} 
} 
return 1; // 与最后一点重叠 
} else { 
return 0; // 新点 
} 
} 
/** 
* 添加一个点 
* 
* @param point 
*/ 
private void addpoint(point point) { 
if (spoints.size() > 0) { 
point lastpoint = spoints.get(spoints.size() - 1); 
int dx = math.abs(lastpoint.getcolnum() - point.getcolnum()); 
int dy = math.abs(lastpoint.getrownum() - point.getrownum()); 
if ((dx > 1 || dy > 1) && (dx == 0 || dy == 0 || dx == dy)) { 
// if ((dx > 1 || dy > 1) && (dx != 2 * dy) && (dy != 2 * dx)) { 
int middleindex = (point.index + lastpoint.index) / 2 - 1; 
point middlepoint = mpoints[middleindex / 3][middleindex % 3]; 
if (middlepoint.state != point.state_check) { 
middlepoint.state = point.state_check; 
spoints.add(middlepoint); 
} 
} 
} 
this.spoints.add(point); 
} 
/** 
* 转换为string 
*/ 
private string topointstring() { 
if (spoints.size() >= pwdminlen && spoints.size() <= pwdmaxlen) { 
stringbuffer sf = new stringbuffer(); 
for (point p : spoints) { 
sf.append(p.index); 
} 
return sf.tostring(); 
} else { 
return ""; 
} 
} 
boolean movingnopoint = false; 
float moveingx, moveingy; 
@override 
public boolean ontouchevent(motionevent event) { 
// 不可操作 
if (!istouch) { 
return false; 
} 
movingnopoint = false; 
float ex = event.getx(); 
float ey = event.gety(); 
boolean isfinish = false; 
boolean redraw = false; 
point p = null; 
switch (event.getaction()) { 
case motionevent.action_down: //点下 
// 如果正在清除密码,则取消 
if (task != null) { 
task.cancel(); 
task = null; 
log.d("task", "touch cancel()"); 
} 
// 删除之前的点 
reset(); 
p = checkselectpoint(ex, ey); 
if (p != null) { 
checking = true; 
} 
mcompletelistener.onprompt("完成后松开手指"); 
break; 
case motionevent.action_move:// 移动 
if (checking) { 
p = checkselectpoint(ex, ey); 
if (p == null) { 
movingnopoint = true; 
moveingx = ex; 
moveingy = ey; 
} 
} 
break; 
case motionevent.action_up:// 提起 
p = checkselectpoint(ex, ey); 
checking = false; 
isfinish = true; 
break; 
} 
if (!isfinish && checking && p != null) { 
int rk = crosspoint(p); 
if (rk == 2) {// 与非最后一重叠 
// reset(); 
// checking = false; 
movingnopoint = true; 
moveingx = ex; 
moveingy = ey; 
redraw = true; 
} else if (rk == 0) {// 一个新点 
p.state = point.state_check; 
addpoint(p); 
redraw = true; 
} 
// rk == 1 
} 
// 是否重画 
if (redraw) { 
} 
if (isfinish) { 
if (this.spoints.size() == 1) { 
this.reset(); 
isfirstpwdempty(); 
} else if (spoints.size() > 0 && spoints.size() < pwdminlen) { 
error(); 
clearpassword(); 
isfirstpwdempty(); 
} else if (mcompletelistener != null) { 
if (this.spoints.size() >= pwdminlen) { 
this.disabletouch(); 
ispwdequal(); 
} 
} 
} 
this.postinvalidate(); 
return true; 
} 
private void isfirstpwdempty() { 
if (textutils.isempty(firstpassword)) { 
mcompletelistener.onprompt("至少需连接4个点,请重试。"); 
} else { 
mcompletelistener.onprompt("请重试"); 
} 
} 
private void ispwdequal() { 
if (textutils.isempty(firstpassword)) { 
mcompletelistener.onprompt("再次绘制图案进行确认"); 
mcompletelistener.oncomplete(topointstring()); 
} else { 
if (firstpassword.equals(topointstring())) { 
mcompletelistener.onprompt("您的新解锁图案"); 
mcompletelistener.oncomplete(topointstring()); 
} else { 
mcompletelistener.onprompt("请重试"); 
error(); 
clearpassword(); 
} 
} 
} 
/** 
* 设置已经选中的为错误 
*/ 
private void error() { 
for (point p : spoints) { 
p.state = point.state_check_error; 
} 
} 
/** 
* 设置为输入错误 
*/ 
public void markerror() { 
markerror(clear_time); 
} 
/** 
* 设置为输入错误 
*/ 
public void markerror(final long time) { 
for (point p : spoints) { 
p.state = point.state_check_error; 
} 
this.clearpassword(time); 
} 
/** 
* 设置为可操作 
*/ 
public void enabletouch() { 
istouch = true; 
} 
/** 
* 设置为不可操作 
*/ 
public void disabletouch() { 
istouch = false; 
} 
private timer timer = new timer(); 
private timertask task = null; 
/** 
* 清除密码 
*/ 
public void clearpassword() { 
clearpassword(clear_time); 
} 
/** 
* 清除密码 
*/ 
public void clearpassword(final long time) { 
if (time > 1) { 
if (task != null) { 
task.cancel(); 
log.d("task", "clearpassword cancel()"); 
} 
postinvalidate(); 
task = new timertask() { 
public void run() { 
reset(); 
postinvalidate(); 
} 
}; 
log.d("task", "clearpassword schedule(" + time + ")"); 
timer.schedule(task, time); 
} else { 
reset(); 
postinvalidate(); 
} 
} 
private string firstpassword; 
public string getfirstpassword() { 
return firstpassword; 
} 
public void setfirstpassword(string firstpassword) { 
this.firstpassword = firstpassword; 
} 
private oncompletelistener mcompletelistener; 
public void setoncompletelistener(oncompletelistener mcompletelistener) { 
this.mcompletelistener = mcompletelistener; 
} 
public interface oncompletelistener { 
void oncomplete(string password); //密码 
void onprompt(string prompt); //提示信息 
} 
}

示例:可支持重绘,需要二次设置密码。

mainactivity.class

import android.app.activity; 
import android.os.bundle; 
import android.util.log; 
import android.view.view; 
import android.widget.button; 
import android.widget.textview; 
import android.widget.toast; 
import soban.ninelockscreen.r; 
public class mainactivity extends activity implements view.onclicklistener, locuspasswordview.oncompletelistener { 
private string tag = main2activity.class.getname(); 
private textview mexplaintv; 
private button mrepaintbtn; 
private button mconfirmbtn; 
private locuspasswordview mpwdview; 
private string firstpassword; 
private string againpassword; 
private boolean isfirst; 
@override 
protected void oncreate(bundle savedinstancestate) { 
super.oncreate(savedinstancestate); 
setcontentview(r.layout.activity_main); 
initviews(); 
} 
private void initviews() { 
mexplaintv = (textview) findviewbyid(r.id.tv_explain); 
mrepaintbtn = (button) findviewbyid(r.id.btn_repaint); 
mconfirmbtn = (button) findviewbyid(r.id.btn_confirm); 
mpwdview = (locuspasswordview) findviewbyid(r.id.mpasswordview2); 
mrepaintbtn.setonclicklistener(this); 
mconfirmbtn.setonclicklistener(this); 
mpwdview.setoncompletelistener(this); 
initchoose(); 
} 
@override 
public void onclick(view view) { 
switch (view.getid()) { 
case r.id.btn_repaint: 
repaint(); 
break; 
case r.id.btn_confirm: 
confirm(); 
break; 
} 
} 
private void repaint() { 
mpwdview.clearpassword(0); 
initchoose(); 
} 
private void confirm() { 
toast.maketext(mainactivity.this, "你设置的密码:" + againpassword, toast.length_short).show(); 
} 
@override 
public void oncomplete(string password) { 
if (isfirst) { 
firstchoose(password); 
} else { 
secondchoose(password); 
} 
log.e(tag, "oncomplete -> " + password); 
} 
@override 
public void onprompt(string prompt) { 
mexplaintv.settext(prompt); 
} 
private void initchoose() { 
isfirst = true; 
firstpassword = ""; 
againpassword = ""; 
mpwdview.setfirstpassword(""); 
mrepaintbtn.setvisibility(view.gone); 
mconfirmbtn.setvisibility(view.gone); 
} 
private void firstchoose(string password) { 
isfirst = false; 
firstpassword = password; 
mpwdview.setfirstpassword(password); 
mpwdview.clearpassword(0); 
mrepaintbtn.setenabled(true); 
mconfirmbtn.setenabled(false); 
mrepaintbtn.setvisibility(view.visible); 
mconfirmbtn.setvisibility(view.visible); 
} 
private void secondchoose(string password) { 
isfirst = true; 
againpassword = password; 
mrepaintbtn.setenabled(true); 
mconfirmbtn.setenabled(true); 
} 
}

布局:activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:gravity="center_horizontal" 
android:orientation="vertical"> 
<linearlayout 
android:id="@+id/bottomlayout" 
android:layout_width="match_parent" 
android:layout_height="50dip" 
android:layout_alignparentbottom="true" 
android:orientation="horizontal"> 
<button 
android:id="@+id/btn_repaint" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_weight="1" 
android:text="重绘" /> 
<button 
android:id="@+id/btn_confirm" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_weight="1" 
android:text="确认" /> 
</linearlayout> 
<soban.ninelockscreen.demo.locuspasswordview 
android:id="@+id/mpasswordview2" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:layout_above="@id/bottomlayout" /> 
<textview 
android:id="@+id/tv_explain" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:layout_above="@id/mpasswordview2" 
android:layout_alignparenttop="true" 
android:background="@color/colorprimary" 
android:gravity="center" 
android:text="绘制解锁图案,请至少连接4个点" 
android:textcolor="#ffffff" /> 
</relativelayout>

以上所述是小编给大家介绍的android 仿小米锁屏实现九宫格解锁功能(无需图片资源),希望对大家有所帮助

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网