九宫格手势锁简单实现

现在好多应用都可以设置手势锁,Android本身也有提供手势图案锁屏。作为Android菜鸟的我,也忍不住想自己动手实现一下。
下面是应用效果图:

思路:

  • 自定义一个View,重写onDraw方法,利用canvas绘制图形。
  • 实现onTouch事件
    • Down Move Down 每次判断是否有在手指的位置相应处理。
  • 直接在布局文件里面 引用View就可以了。

注意:

  • 我在实现的过程中遇到一个问题,导致应用奔溃,日志信息也看不懂。最后是在stackoverflow上找到解决方法的。自定义的View一定要实现 两个参数的构造函数(即 SudokuView(Context context, AttributeSet attrs) )
  • onTouchEvent 方法的返回值一定要是 true,不然就无法相应 Move 和Up 事件了【只会鸟Down~】

下面直接上代码
Cell 类(存储圆点的信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.example.mummyding.sudokulock;
/**
* Created by mummyding on 15-7-17.
*/
public class Cell {
private int x;
private int y;
private boolean isSelected;
public boolean isSelected() {
return isSelected;
}
public void setIsSelected(boolean isSelected) {
this.isSelected = isSelected;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}

自定义View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package com.example.mummyding.sudokulock;
import android.app.Notification;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import java.lang.reflect.Type;
/**
* Created by mummyding on 15-7-17.
*/
public class SudokuView extends View {
private static final int COUNT = 3;
Cell [] cell;
int [] selectedCell;
int RADIUS ,OFFSET;
int ScreenWidth,ScreenHeight;
int startX,startY,selectedCount,lastX,lastY;
boolean drawFinish ;
Paint mPaint ;
public SudokuView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void initCell(){
//初始化各点
for(int i = 0 ; i < COUNT ; i++ )
for (int j = 0 ; j < COUNT ; j++) {
cell[i * COUNT + j].setIsSelected(false);
cell[i * COUNT + j].setX(startX + OFFSET * j - RADIUS/2);
cell[i * COUNT + j].setY(startY + OFFSET * i - RADIUS/2);
}
}
private void init(Context context){
cell = new Cell[COUNT * COUNT];
selectedCell = new int[COUNT*COUNT];
mPaint = new Paint();
//获取屏幕的宽度和高度
WindowManager manager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm=new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
ScreenWidth = dm.widthPixels;
ScreenHeight = dm.heightPixels;
this.setMinimumWidth(ScreenWidth);
this.setMinimumHeight(ScreenHeight);
drawFinish = false; //是否绘制完成
selectedCount = 0; //已经选中的点个数
RADIUS = ScreenWidth / 12; //半径
OFFSET = ScreenWidth / 4 ; //点之间的间距
startX = OFFSET; //起始点横坐标
startY = (ScreenHeight - OFFSET * 2) / 2; //起始点纵坐标
for(int i = 0 ; i < COUNT*COUNT ; i++){
cell[i] = new Cell();
}
initCell();
}
int inWhichCircle(int x, int y){
for(int i = 0 ; i < COUNT*COUNT ; i++){
if(cell[i].isSelected() == false){
if((Math.abs(x - cell[i].getX())<RADIUS) && Math.abs(y - cell[i].getY()) < RADIUS){
return i;
}
}
}
return -1;
}
void drawCell(Canvas canvas){
for(int i = 0 ; i < COUNT*COUNT ; i++){
//选择画笔&&画圆
if(cell[i].isSelected()){
mPaint.setColor(Color.GREEN);
mPaint.setStrokeWidth(10);
//画圆
canvas.drawCircle(cell[i].getX(),cell[i].getY(),RADIUS,mPaint);
mPaint.setStrokeWidth(20);
//画点
canvas.drawPoint(cell[i].getX(),cell[i].getY(),mPaint);
} else {
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(5);
//画圆
canvas.drawCircle(cell[i].getX(),cell[i].getY(),RADIUS,mPaint);
//画点
canvas.drawPoint(cell[i].getX(),cell[i].getY(),mPaint);
}
}
}
void drawLine(Canvas canvas) {
mPaint.setColor(Color.GREEN);
mPaint.setStrokeWidth(5);
for(int i = 1 ; i < selectedCount ; i++){
Cell lastCell = cell[selectedCell[i-1]],thisCell = cell[selectedCell[i]];
canvas.drawLine(lastCell.getX(), lastCell.getY(), thisCell.getX(), thisCell.getY(), mPaint);
}
if(selectedCount !=0 &&(lastX !=0 || lastY != 0)){
canvas.drawLine(cell[selectedCell[selectedCount - 1]].getX(), cell[selectedCell[selectedCount - 1]].getY(), lastX, lastY, mPaint);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint = new Paint();
mPaint.setStrokeWidth(5);;
mPaint.setAntiAlias(true);
mPaint.setColor(Color.GRAY);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setStyle(Paint.Style.STROKE);
drawCell(canvas);
drawLine(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int tmpIndex;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
drawFinish = false;
if((tmpIndex = inWhichCircle((int)event.getX(),(int)event.getY())) != -1){
cell[tmpIndex].setIsSelected(true);
selectedCell[selectedCount++] = tmpIndex;
this.postInvalidate();
}
break;
case MotionEvent.ACTION_MOVE:
if(drawFinish == false){
if((tmpIndex = inWhichCircle((int)event.getX(),(int)event.getY())) != -1){
cell[tmpIndex].setIsSelected(true);
selectedCell[selectedCount++] = tmpIndex;
}
}
lastX = (int) event.getX();
lastY = (int) event.getY();
this.postInvalidate();
break;
case MotionEvent.ACTION_UP:
drawFinish = true;
lastX = lastY = 0;
selectedCount = 0;
initCell();
this.postInvalidate();
break;
}
return true;
}
}

布局布局[XML]

1
2
3
4
5
6
7
8
9
10
11
12
13
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:background="@color/material_blue_grey_800"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<com.example.mummyding.sudokulock.SudokuView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</RelativeLayout>

完整代码 : https://github.com/MummyDing/SudokuLock

【转载请注明出处】
Author: MummyDing

Contents
|