Android-九宫格

直接上代码,不过有三点待改善;

  • 手指必须划过圆,才能连接到这个圆。
  • 当连到最后一个圆时,会直接出结果,而不是等抬手再出结果。
  • 必须连接5个及以上。

示例;

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
tools:context=".MainActivity">

<com.example.myapplication.NineGridView
android:id="@+id/nine"
android:layout_width="400dp"
android:layout_height="400dp"
android:layout_gravity="center"/>
</FrameLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NineGridView nine = findViewById(R.id.nine);
nine.setOnPasswordFinishListener(new NineGridView.OnPasswordFinishListener() {
@Override
public void onPasswrodFinish(String password) {
Toast.makeText(MainActivity.this, "你输入的密码是" + password, Toast.LENGTH_LONG).show();
}
});
}
}
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/**
* 九宫格
* 一个问题,手指必须划过圆
*/
public class NineGridView extends View {

private Paint paint;
public static final int raduis = 60;
public static final int raduisS = 30;
private float curr_x, curr_y;
private boolean isOver = false;
private List<Point> points = new ArrayList<>();
//当前用户选中的圆 0-8
private List<Integer> mList = new ArrayList<>();

/**
* 构造函数
* @param context
*/
public NineGridView(Context context) {
super(context);
init();
}

public NineGridView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

/**
* 初始化画笔
*/
public void init() {
paint = new Paint();
// 抗锯齿
paint.setAntiAlias(true);
// 防抖动
paint.setDither(true);
paint.setStrokeWidth(10);
// 画笔颜色 #5AA9FE
paint.setColor(Color.rgb(0x5a, 0xa9, 0xfe));
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getWidth() != 0 && getHeight() != 0) {
//算出9个点
int width = getWidth() / 4;
int height = getHeight() / 4;
//第一个点 = width,height;
//第二个点 = width*2 height;
//。。。
//第四个点 = width / height*2;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
Point point = new Point((j + 1) * width, (i + 1) * height);
points.add(point);
}
}
}
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//判断mList.size>0;
if (mList.size() > 0) {
//从最后一个圆中引一条线到 手指地方
Point point = points.get(mList.get(mList.size() - 1));
canvas.drawLine(point.x, point.y, curr_x, curr_y, paint);
}
//如果mList>1
if (mList.size() > 1) {
//0,1
for (int i = 0; i < mList.size() - 1; i++) {
Point start = points.get(mList.get(i));
Point end = points.get(mList.get(i + 1));
canvas.drawLine(start.x, start.y, end.x, end.y, paint);
}
}
paint.setColor(Color.WHITE);
for (Point point : points) {
canvas.drawCircle(point.x, point.y, raduis, paint);
}
paint.setColor(Color.rgb(0x5a, 0xa9, 0xfe));//#5AA9FE
paint.setStyle(Paint.Style.STROKE);
//先画圆变成了最后画圆 //遮住后面的线
paint.setStrokeWidth(2);
for (Point point : points) {
canvas.drawCircle(point.x, point.y, raduis, paint);
}
//画实心圆
paint.setStyle(Paint.Style.FILL_AND_STROKE);
for (Integer i : mList) {
Point point = points.get(i);
canvas.drawCircle(point.x, point.y, raduisS, paint);
}
}


@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isOver = false;
//判断是否在圆心内,并且画圆
int index = isOnClircle(x, y);
if (index != -1) {
mList.add(index);
}
curr_x = x;
curr_y = y;
break;
case MotionEvent.ACTION_MOVE:
if (!isOver) {
curr_x = x;
curr_y = y;
//引一条线到手指的地方,如果手指滑动到圆中,并且该圆还没有被选中,那用一条线连接两个圆,在从该圆引一条线到与手指
int i = isOnClircle(x, y);
if (i != -1 && !mList.contains(i)) {
mList.add(i);
}
if (mList.size() == 9) {
returnData();
mList.clear();
isOver = true;
}
}
break;
case MotionEvent.ACTION_UP:
//密码设置完毕,需要回调
//密码验证完毕, 需要回调
//密码返回回去
if (mList.size() > 4) {//56789
returnData();
}
mList.clear();
break;
default:
break;
}
invalidate();
return true;
}


public void returnData() {
if (onPasswordFinishListener != null) {
String password = "";
for (int i = 0; i < mList.size(); i++) {
password += mList.get(i) + 1;
}
onPasswordFinishListener.onPasswrodFinish(password);
}
}

/**
* 用户按下的地方
* @param x
* @param y
* @return
*/
public int isOnClircle(float x, float y) {
for (int i = 0; i < points.size(); i++) {
//判断圆心到点的距离
Point point = points.get(i);
if ((x - point.x) * (x - point.x) + (y - point.y) * (y - point.y) < raduis * raduis) {
return i;
}
}
return -1;
}

/**
* 回调
*/
private OnPasswordFinishListener onPasswordFinishListener;

public void setOnPasswordFinishListener(OnPasswordFinishListener onPasswordFinishListener) {
this.onPasswordFinishListener = onPasswordFinishListener;
}

public interface OnPasswordFinishListener {
void onPasswrodFinish(String password);
}
}

传送门:GitHub