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");
}
}
上面的代碼我們可以生成一個方法,在用戶按下和移動的操作中調用即可
好了,九宮鎖到此結束,有更好思路的請告知,以上文章如有錯誤,請熱情指正