1 package com.rxx.view;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.Timer;
6 import java.util.TimerTask;
7 import android.content.Context;
8 import android.graphics.Canvas;
9 import android.graphics.Color;
10 import android.graphics.Paint;
11 import android.graphics.Path;
12 import android.util.AttributeSet;
13 import android.view.MotionEvent;
14 import android.view.View;
15
16 /**
17 * 自定义锁屏View
18 */
19 public class GestureLockView extends View {
20 /** 解锁密码key */
21 private String key = "";
22 private OnGestureFinishListener onGestureFinishListener;
23
24 /** 解锁圆点数组 */
25 private LockCircle[] cycles;
26 /** 存储触碰圆的序列 */
27 private List<Integer> linedCycles = new ArrayList<Integer>();
28
29 // 画笔
30 /** 空心外圆 */
31 private Paint paintNormal;
32 /** 点击后内部圆 */
33 private Paint paintInnerCycle;
34 /** 画路径 */
35 private Paint paintLines;
36 private Path linePath = new Path();
37
38 /** 当前手指X,Y位置 */
39 private int eventX, eventY;
40
41 /** 能否操控界面绘画 */
42 private boolean canContinue = true;
43 /** 验证结果 */
44 private boolean result;
45 private Timer timer;
46
47 /** 未选中颜色 */
48 private final int NORMAL_COLOR = Color.parseColor("#959BB4");
49 /** 错误颜色 */
50 private final int ERROE_COLOR = Color.parseColor("#FF2525"); // 正常外圆颜色
51 /** 选中时颜色 */
52 private final int TOUCH_COLOR = Color.parseColor("#409DE5"); // 选中内圆颜色
53
54 // =================================start=构造方法========================
55 public GestureLockView(Context context, AttributeSet attrs, int defStyle) {
56 super(context, attrs, defStyle);
57 init();
58 }
59
60 public GestureLockView(Context context, AttributeSet attrs) {
61 this(context, attrs, 0);
62 }
63
64 public GestureLockView(Context context) {
65 this(context, null);
66 }
67
68 // ===============================end=构造方法========================
69
70 /** 初始化 */
71 public void init() {
72 paintNormal = new Paint();
73 paintNormal.setAntiAlias(true);
74 paintNormal.setStrokeWidth(5);
75 paintNormal.setStyle(Paint.Style.STROKE);
76
77 paintInnerCycle = new Paint();
78 paintInnerCycle.setAntiAlias(true);
79 paintInnerCycle.setStyle(Paint.Style.FILL);
80
81 paintLines = new Paint();
82 paintLines.setAntiAlias(true);
83 paintLines.setStyle(Paint.Style.STROKE);
84 paintLines.setStrokeWidth(10);
85
86 }
87
88 @Override
89 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
90 int specMode = MeasureSpec.getMode(widthMeasureSpec);
91 int spceSize = MeasureSpec.getSize(widthMeasureSpec);
92 heightMeasureSpec = MeasureSpec.makeMeasureSpec(
93 (int) (spceSize * 0.85 + 0.5f), specMode);
94 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
95 }
96
97 @Override
98 protected void onLayout(boolean changed, int left, int top, int right,
99 int bottom) {
100 super.onLayout(changed, left, top, right, bottom);
101 int perWidthSize = getWidth() / 7;
102 int perHeightSize = getHeight() / 6;
103 /** 初始化圆的参数 */
104 if (cycles == null && (perWidthSize > 0) && (perHeightSize > 0)) {
105 cycles = new LockCircle[9];
106 for (int i = 0; i < 3; i++) {
107 for (int j = 0; j < 3; j++) {
108 LockCircle lockCircle = new LockCircle();
109 lockCircle.setNum(i * 3 + j);
110 lockCircle.setOx(perWidthSize * (j * 2 + 1.5f) + 0.5f);
111 lockCircle.setOy(perHeightSize * (i * 2 + 1) + 0.5f);
112 lockCircle.setR(perWidthSize * 0.6f);
113 cycles[i * 3 + j] = lockCircle;
114 }
115 }
116 }
117
118 }
119
120 public void setKey(String key) {
121 this.key = key;
122 }
123
124 public void setOnGestureFinishListener(
125 OnGestureFinishListener onGestureFinishListener) {
126 this.onGestureFinishListener = onGestureFinishListener;
127 }
128
129 /** 手势输入完成后回调接口 */
130 public interface OnGestureFinishListener {
131 /** 手势输入完成后回调函数 */
132 public void OnGestureFinish(boolean success, String key);
133 }
134
135 /** 监听手势 */
136 @Override
137 public boolean onTouchEvent(MotionEvent event) {
138 if (canContinue) {
139 switch (event.getAction()) {
140 case MotionEvent.ACTION_DOWN:
141 case MotionEvent.ACTION_MOVE:
142 eventX = (int) event.getX();
143 eventY = (int) event.getY();
144 for (int i = 0; i < cycles.length; i++) {
145 if (cycles[i].isPointIn(eventX, eventY)) {
146 cycles[i].setOnTouch(true);
147 if (!linedCycles.contains(cycles[i].getNum())) {
148 linedCycles.add(cycles[i].getNum());
149 }
150 }
151 }
152 break;
153 case MotionEvent.ACTION_UP:
154 // 手指离开暂停触碰
155 canContinue = false;
156 StringBuffer stringBuffer = new StringBuffer();
157 for (int i = 0; i < linedCycles.size(); i++) {
158 stringBuffer.append(linedCycles.get(i));
159 }
160 result = key.equals(stringBuffer.toString());
161 if (onGestureFinishListener != null && linedCycles.size() > 0) {
162 onGestureFinishListener.OnGestureFinish(result,
163 stringBuffer.toString());
164 }
165 timer = new Timer();
166 timer.schedule(new TimerTask() {
167 @Override
168 public void run() {
169 eventX = eventY = 0;
170 for (int i = 0; i < 9; i++) {
171 cycles[i].setOnTouch(false);
172 }
173 linedCycles.clear();
174 linePath.reset();
175 canContinue = true;
176 postInvalidate();// 在非ui线程刷新界面
177 }
178 }, 1000);
179 break;
180 }
181 invalidate();
182 }
183 return true;
184 }
185
186 @Override
187 protected void onDraw(Canvas canvas) {
188 super.onDraw(canvas);
189 int cycleSize = cycles.length;
190 for (int i = 0; i < cycleSize; i++) {
191 // 画完并且错误
192 if (!canContinue && !result) {
193 if (cycles[i].isOnTouch()) {
194 drawInnerCycle(cycles[i], canvas, ERROE_COLOR);
195 drawOutsideCycle(cycles[i], canvas, ERROE_COLOR);
196 } else
197 drawOutsideCycle(cycles[i], canvas, NORMAL_COLOR);
198 }
199 // 绘画中
200 else {
201 if (cycles[i].isOnTouch()) {
202 drawInnerCycle(cycles[i], canvas, TOUCH_COLOR);
203 drawOutsideCycle(cycles[i], canvas, TOUCH_COLOR);
204 } else
205 drawOutsideCycle(cycles[i], canvas, NORMAL_COLOR);
206 }
207 }
208
209 if (!canContinue && !result) {
210 drawLine(canvas, ERROE_COLOR);
211 } else {
212 drawLine(canvas, TOUCH_COLOR);
213 }
214
215 }
216
217 /** 画空心圆 */
218 private void drawOutsideCycle(LockCircle lockCircle, Canvas canvas,
219 int color) {
220 paintNormal.setColor(color);
221 canvas.drawCircle(lockCircle.getOx(), lockCircle.getOy(),
222 lockCircle.getR(), paintNormal);
223 }
224
225 /** 画横线 */
226 private void drawLine(Canvas canvas, int color) {
227 // 构建路径
228 linePath.reset();
229 if (linedCycles.size() > 0) {
230 int size = linedCycles.size();
231 for (int i = 0; i < size; i++) {
232 int index = linedCycles.get(i);
233 float x = cycles[index].getOx();
234 float y = cycles[index].getOy();
235 if (i == 0) {
236 linePath.moveTo(x, y);
237 } else {
238 linePath.lineTo(x, y);
239 }
240 }
241 if (canContinue) {
242 linePath.lineTo(eventX, eventY);
243 } else {
244 linePath.lineTo(
245 cycles[linedCycles.get(linedCycles.size() - 1)].getOx(),
246 cycles[linedCycles.get(linedCycles.size() - 1)].getOy());
247 }
248 paintLines.setColor(color);
249 canvas.drawPath(linePath, paintLines);
250 }
251 }
252
253 /** 画中心圆圆 */
254 private void drawInnerCycle(LockCircle myCycle, Canvas canvas, int color) {
255 paintInnerCycle.setColor(color);
256 canvas.drawCircle(myCycle.getOx(), myCycle.getOy(),
257 myCycle.getR() / 3f, paintInnerCycle);
258 }
259
260 /**
261 * 每个圆点类
262 */
263 class LockCircle {
264 /** 圆心横坐标 */
265 private float ox;
266 /** 圆心纵坐标 */
267 private float oy;
268 /** 半径长度 */
269 private float r;
270 /** 代表数值 */
271 private Integer num;
272 /** 是否选择:false=未选中 */
273 private boolean onTouch;
274
275 public float getOx() {
276 return ox;
277 }
278
279 public void setOx(float ox) {
280 this.ox = ox;
281 }
282
283 public float getOy() {
284 return oy;
285 }
286
287 public void setOy(float oy) {
288 this.oy = oy;
289 }
290
291 public void setOy(int oy) {
292 this.oy = oy;
293 }
294
295 public float getR() {
296 return r;
297 }
298
299 public void setR(float r) {
300 this.r = r;
301 }
302
303 public Integer getNum() {
304 return num;
305 }
306
307 public void setNum(Integer num) {
308 this.num = num;
309 }
310
311 public boolean isOnTouch() {
312 return onTouch;
313 }
314
315 public void setOnTouch(boolean onTouch) {
316 this.onTouch = onTouch;
317 }
318
319 /** 判读传入位置是否在圆心内部 */
320 public boolean isPointIn(int x, int y) {
321 double distance = Math.sqrt((x - ox) * (x - ox) + (y - oy)
322 * (y - oy));
323 return distance < r;
324 }
325 }
326 }
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 android:layout_width="fill_parent"
3 android:layout_height="fill_parent"
4 android:background="#232736"
5 android:gravity="center"
6 android:orientation="vertical" >
7
8 <!-- 小头像 -->
9 <ImageView
10 android:layout_width="70dp"
11 android:layout_height="70dp"
12 android:src="@drawable/tempfenlei" />
13
14 <TextView
15 android:id="@+id/textview"
16 android:layout_width="wrap_content"
17 android:layout_height="wrap_content"
18 android:layout_marginTop="10dp"
19 android:text=""
20 android:textColor="#FF2525"
21 android:textSize="16sp"
22 android:visibility="invisible" />
23
24 <com.rxx.view.GestureLockView
25 android:id="@+id/gestureLockView"
26 android:layout_width="wrap_content"
27 android:layout_height="wrap_content" />
28
29 <LinearLayout
30 android:layout_width="fill_parent"
31 android:layout_height="wrap_content"
32 android:orientation="horizontal"
33 android:padding="10dp" >
34
35 <TextView
36 android:layout_width="fill_parent"
37 android:layout_height="wrap_content"
38 android:layout_weight="1"
39 android:gravity="center"
40 android:text="管理手势密码"
41 android:textColor="#585C6E"
42 android:textSize="16sp" />
43
44 <TextView
45 android:layout_width="fill_parent"
46 android:layout_height="wrap_content"
47 android:layout_weight="1"
48 android:gravity="center"
49 android:text="登陆其他账号"
50 android:textColor="#585C6E"
51 android:textSize="16sp" />
52 </LinearLayout>
53
54 </LinearLayout>
1 package com.rxx.gesturelockdemo;
2
3 import android.app.Activity;
4 import android.graphics.Color;
5 import android.os.Bundle;
6 import android.view.View;
7 import android.view.animation.Animation;
8 import android.view.animation.TranslateAnimation;
9 import android.widget.TextView;
10
11 import com.rxx.view.GestureLockView;
12 import com.rxx.view.GestureLockView.OnGestureFinishListener;
13
14 public class MainActivity extends Activity {
15
16 private GestureLockView gestureLockView;
17 private TextView textview;
18 private Animation animation;
19
20 @Override
21 protected void onCreate(Bundle savedInstanceState) {
22 super.onCreate(savedInstanceState);
23 setContentView(R.layout.activity_main);
24 init();
25 }
26
27 /** 初始化 */
28 public void init() {
29 gestureLockView = (GestureLockView) findViewById(R.id.gestureLockView);
30 textview = (TextView) findViewById(R.id.textview);
31 animation = new TranslateAnimation(-20, 20, 0, 0);
32 animation.setDuration(50);
33 animation.setRepeatCount(2);
34 animation.setRepeatMode(Animation.REVERSE);
35 // 设置密码
36 gestureLockView.setKey("1");
37 // 手势完成后回调
38 gestureLockView
39 .setOnGestureFinishListener(new OnGestureFinishListener() {
40 @Override
41 public void OnGestureFinish(boolean success, String key) {
42 if (success) {
43 textview.setTextColor(Color.parseColor("#FFFFFF"));
44 textview.setVisibility(View.VISIBLE);
45 textview.setText("密码正确!");
46 textview.startAnimation(animation);
47 } else {
48 textview.setTextColor(Color.parseColor("#FF2525"));
49 textview.setVisibility(View.VISIBLE);
50 textview.setText("密码错误!");
51 textview.startAnimation(animation);
52 }
53 }
54 });
55 }
56 }