Android九宫格锁屏
2017-01-05 本文已影响201人
一s独秀
Android 九宫格锁屏(已更新,添加了用户操作记录密码,更加完善,更新的在下面)
此demo的重点就在于九宫点的绘制,与用户操作手势的监听交互

实现思路1(点的绘制)
- 在绘制之前首先确定绘制九点整体的位置,这里将九点确定在居中
- 要想将九点分别按顺序绘制在屏幕中,要知道屏幕的宽高
- 因为九点为三行三列所以我们可以讲中间绘制九点的区域给一个正方形,将正方形在分为4 × 4的小正方形
- 接下来根据屏幕的宽高确定手机此时的横竖屏状态分别设置不同的偏移量和space(space为4×4小方格之一的边长)的值
此图为绘制九点之前的思路(竖屏状态)

下面我们先新建一个类 SudokuLockViewextends
(继承)View
,实现继承的方法
重写onDraw
方法,在onDraw
方法中首先判断要绘制的九点的位置是否初始化,如果没有则实现九点初始化的方法
private void initView() {
/**
* 屏幕宽高
*/
int pHigth = metrics.heightPixels;
int pWidth = metrics.widthPixels;
/**
* X,Y的偏移量
*/
float offsetX;
float offsetY;
float space; //小方格边长
/**
* 判断横竖屏设置对应的值
*/
if (pHigth > pWidth){
offsetX = 0;
offsetY = (pHigth - pWidth)/2;
space = pWidth/4;
}else {
offsetX = (pWidth - pHigth)/2;
offsetY = 0;
space = pHigth/4;
}
//以下可以用双层for循环更简便
/**one lines**/
myPoint[0][0] = new MyPoint(offsetX+space,offsetY+space);
myPoint[0][1] = new MyPoint(offsetX+space*2,offsetY+space);
myPoint[0][2] = new MyPoint(offsetX+space*3,offsetY+space);
/**two lines**/
myPoint[1][0] = new MyPoint(offsetX+space,offsetY+space*2);
myPoint[1][1] = new MyPoint(offsetX+space*2,offsetY+space*2);
myPoint[1][2] = new MyPoint(offsetX+space*3,offsetY+space*2);
/**three lines**/
myPoint[2][0] = new MyPoint(offsetX+space,offsetY+space*3);
myPoint[2][1] = new MyPoint(offsetX+space*2,offsetY+space*3);
myPoint[2][2] = new MyPoint(offsetX+space*3,offsetY+space*3);
}
初始化点的位置之后就可以开始绘制点了(此处的九点可以通过Paint
绘制圆形的图标,也可以直接定义一个图片资源,直接将图片资源绘制出来),此处用的第二种方法,同样在初始的方法中添加资源图标的初始
/**添加点的图片资源**/
nBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.onetests);
sBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.twotests);
eBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.threetests);
之后就可以直接绘制出
private void drawPoint(Canvas canvas) {
for (int i = 0;i<myPoint.length;i++){
for (int j = 0;j<myPoint[i].length;j++){
/**
* 当然,此处可以判断九点的不同的状态,在绘制(正常的、选中的,错误的)
*
* @bitR 为图片资源的半径,因为画笔所绘制的不会是从中心电绘制,而是从左上角开始绘制,在这里x,y各减去半径,就会以图标中心的位置开始绘制
*/
canvas.drawBitmap(sBitmap,myPoint[i][j].x-bitR,myPoint[i][j].y-bitR,paint);
}
}
}
好了,现在在XML文件中把我们自定义的这个View添加一下,运行看看,九点的效果就出来了
实现思路2(用户操作)
- 在用户手势监听的方法
onTouchEvent
中分别有三种状态(Down
·Move
·Up
) - 首先在用户手指点下的时候,就要以x,y生成一个点,并且将点返回,判断点的位置是否为九点中任一点的位置,如果是添加选中的点,并改变点的状态
- 当用户手指移动时,同上,先判断是否选择的是九点中任意点,如果是,在此处再次判断,次点是否已经包含在选中点的集合中,如果没有包含,改变点的状态并添加
- 在用户手指抬起的时候,先判断所绘制的点的总数是否大于规定的最小数量,分别以点的不同状态显示所选最小数是否满足,最后在判断,当用户操作屏幕后,并且选中点的数量大于0,那么就关闭绘制状态
下面为当用户手指点下并且滑动的时候生成的点,并且返回为选中的九点的任一点,没选中的返回为null
/**
* 返回是否选择的是点
*/
private int[] getSelectPoint() {
//MyPoint自定义的点的类 ,用户手指按下时以x,y生成的点
MyPoint begainSelectPoint = new MyPoint(moveX,moveY);
for (int i = 0;i<myPoint.length;i++){
for (int j = 0;j<myPoint[i].length;j++){
//判断距离将选择的点的位置否和一定条件时,为选中
if (myPoint[i][j].distance(begainSelectPoint) < bitR){
//定义长度为2的数组,返回选中点的X,Y
int[] result = new int[2];
result[0] = i;
result[1] = j;
return result;
}
}
}
return null;//选中的不是九点的任一点时
}
下面上一下onTouchEvent
的方法(在此方法中在用户没操作的时候都要显示选中点的状态,所以要及时更新View,可以用this.postInvalidate();
方法,及时更新)
@Override
public boolean onTouchEvent(MotionEvent event) {
moveX = event.getX();
moveY = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if (isDrawing){
getSelect = getSelectPoint();//用int[]的类型接收
if (getSelect != null){
x = getSelect[0];//x
y = getSelect[1];//y
myPoint[x][y].start = MyPoint.SELECT;//设置点的状态
allPoint.add(myPoint[x][y]);//添加点到选择点的集合
}
}
break;
case MotionEvent.ACTION_MOVE:
if (isDrawing){
getSelect = getSelectPoint();
if (getSelect != null){
x = getSelect[0];
y = getSelect[1];
if (!allPoint.contains(myPoint[x][y])){//判断是否已经包含此点
myPoint[x][y].start = MyPoint.SELECT;
allPoint.add(myPoint[x][y]);
}
}
}
break;
case MotionEvent.ACTION_UP:
if (isDrawing){
if (allPoint.size() <= 3 && allPoint.size()>0){
Toast.makeText(getContext(),"至少不少于四点",Toast.LENGTH_SHORT).show();
for (int i = 0;i<allPoint.size();i++){
allPoint.get(i).start = MyPoint.ERROR;
}
}
}
if (allPoint.size() > 0){
isDrawing = false;
}
break;
}
this.postInvalidate();//及时更新
return true;
}
在onTouchEvent
方法之后就可以绘制线了,线的绘制是以两点划线,并且,每次讲第二次选择的线赋值为初始点,下面给下选中九点的任一点,和没选中是线的绘制
private void drawPointLines(Canvas canvas) {
if (allPoint.size() > 0){
MyPoint A = allPoint.get(0);
for (int a = 1;a<allPoint.size();a++){
MyPoint B = allPoint.get(a);
drawLines(canvas,A,B);//此为选中九点时的划线的方法
A = B;
}
if (isDrawing){
drawLines(canvas,A,new MyPoint(moveX,moveY));//当处于绘制状态时,没有选中时,划线就是一手指移动而绘制
}
}
}
绘制线的方法,判断选择的点的个数,绘制不同状态的线
/**
* 通过两点绘制线
* @param canvas
* @param a
* @param b
*/
private void drawLines(Canvas canvas, MyPoint a, MyPoint b) {
if (a.start == MyPoint.ERROR){
canvas.drawLine(a.x,a.y,b.x,b.y,epaint);
}else {
canvas.drawLine(a.x,a.y,b.x,b.y,paint);
}
}
用户操作密码记录
- 上面我们在用户操作的方法
onTouchEvent
中用三种状态,我们只需在用户按下和移动的状态中添加判断的方法,判断用户选择的是当前的哪一个点,我们在给每一个点设置不同的标志值,当用户保存时,我们可以将用户的选择点的标志保存起来即可(下面上下代码)
private void setPassWord(int x, int y) {
if (myPoint[x][y] == myPoint[0][0]){
list.add("1");
}else if (myPoint[x][y] == myPoint[0][1]){
list.add("2");
}else if (myPoint[x][y] == myPoint[0][2]){
list.add("3");
}else if (myPoint[x][y] == myPoint[1][0]){
list.add("4");
}else if (myPoint[x][y] == myPoint[1][1]){
list.add("5");
}else if (myPoint[x][y] == myPoint[1][2]){
list.add("6");
}else if (myPoint[x][y] == myPoint[2][0]){
list.add("7");
}else if (myPoint[x][y] == myPoint[2][1]){
list.add("8");
}else if (myPoint[x][y] == myPoint[2][2]){
list.add("9");
}
}
上面的代码我们可以生成一个方法,在用户按下和移动的操作中调用即可
好了,九宫锁到此结束,有更好思路的请告知,以上文章如有错误,请热情指正