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 }