由上图,可以看出,图案中手势的记录是1-9或0-8的,保存的顺序就是密码,当然有些是可以重复的,为了安全,肯定不能直接存原顺序,一定是要加密处理的,如MD5或Hash散列。 (作者: a day a better) 图案解锁中自定义View,是其中最为关键的一部分。下面是自定义LockView的实现,里面的注释写的很详细了。
<span style="font-size:14px;">package com.example.patternlock;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class LockView extends View {
private boolean inited = false;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);// 抗锯齿
Paint pressPaint = new Paint(); //按下时的画笔
Paint errorPaint = new Paint(); //错误时的画笔
private Bitmap bitmapPointError;
private Bitmap bitmapPointPress;
private Bitmap bitmapPointNormal;
private float bitmapR; // 点的半径
private boolean isDraw = false; //是否正在绘制
float mouseX, mouseY;
private Point [][] points = new Point[3][3];
private ArrayList<point> pointList = new ArrayList<point>(); //保存经过的点
private ArrayList<integer> passList = new ArrayList<integer>();
private OnDrawFinishedListener listener;
public LockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public LockView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public LockView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mouseX = event.getX();
mouseY = event.getY();
int [] ij;
int i , j;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
resetPoints();
ij = getSelectedPoint();
if(ij != null){
isDraw = true;
i = ij[0];
j = ij[1];
points[i][j].state = Point.STATE_PRESS;
pointList.add(points[i][j]);
passList.add(i * 3 + j);
}
break;
case MotionEvent.ACTION_MOVE:
if(isDraw){
ij = getSelectedPoint();
if(ij != null){
i = ij[0];
j = ij[1];
if(!pointList.contains(points[i][j])){
points[i][j].state = Point.STATE_PRESS;
pointList.add(points[i][j]);
passList.add(i * 3 + j);
}
}
}
break;
case MotionEvent.ACTION_UP:
boolean valid = false;
if(listener != null && isDraw){
valid = listener.OnDrawFinished(passList);
}
if(!valid){
for (Point p:pointList) {
p.state = Point.STATE_ERROR;
}
}
isDraw = false;
break;
default:
break;
}
this.postInvalidate();
return true;
}
private int[] getSelectedPoint() {
Point pMouse = new Point(mouseX,mouseY);
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
if(points[i][j].distance(pMouse) < bitmapR){
int [] result = new int [2];
result[0] = i;
result[1] = j;
return result;
}
}
}
return null;
}
public void resetPoints() {
passList.clear();
pointList.clear();
for (int i = 0; i < points.length; i++)
{
for (int j = 0; j < points[i].length; j++)
{
points[i][j].state = Point.STATE_NORMOL;
}
}
this.postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(!inited){
init();
}
drawPoints(canvas);
if(pointList.size() > 0){ //画线 2->3,3->5 ...
Point a = pointList.get(0);
for (int i = 1;i < pointList.size(); i++)
{
Point b = pointList.get(i);
drawLine(canvas, a, b);
a = b;
}
if(isDraw){ // 画最后一个点
drawLine(canvas, a, new Point(mouseX, mouseY));
}
}
}
private void drawLine(Canvas canvas, Point a, Point b) {
if(a.state == Point.STATE_ERROR){
canvas.drawLine(a.x, a.y, b.x, b.y, errorPaint);
}
else if(a.state == Point.STATE_PRESS){
canvas.drawLine(a.x, a.y, b.x, b.y, pressPaint);
}
}
private void drawPoints(Canvas canvas) {
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
if(points[i][j].state == Point.STATE_NORMOL){
// normol
canvas.drawBitmap(bitmapPointNormal, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);
}
else if(points[i][j].state == Point.STATE_PRESS){
// press
canvas.drawBitmap(bitmapPointPress, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);
}
else{
// error
canvas.drawBitmap(bitmapPointError, points[i][j].x - bitmapR, points[i][j].y - bitmapR, paint);
}
}
}
}
private void init() {
pressPaint.setColor(Color.YELLOW);
pressPaint.setStrokeWidth(4);
errorPaint.setColor(Color.RED);
errorPaint.setStrokeWidth(4);
bitmapPointError = BitmapFactory.decodeResource(getResources(), R.drawable.error);
bitmapPointNormal = BitmapFactory.decodeResource(getResources(), R.drawable.normal);
bitmapPointPress = BitmapFactory.decodeResource(getResources(), R.drawable.press);
bitmapR = bitmapPointError.getWidth() / 2; //三种点的大小一样
int width = getWidth();
int height = getHeight();
int offset = Math.abs(width - height) / 2;
int offsetX, offsetY;
int space;
if(width > height){
space = height / 4;
offsetX = offset;
offsetY = 0;
}
else{
space = width / 4;
offsetX = 0;
offsetY = offset;
}
points[0][0] = new Point(offsetX +space , offsetY + space);
points[0][1] = new Point(offsetX + 2*space , offsetY + space);
points[0][2] = new Point(offsetX + 3 * space , offsetY + space);
points[1][0] = new Point(offsetX +space, offsetY + 2 * space);
points[1][1] = new Point(offsetX + 2 * space , offsetY + 2 * space);
points[1][2] = new Point(offsetX + 3 * space , offsetY + 2 * space);
points[2][0] = new Point(offsetX +space, offsetY + 3 * space);
points[2][1] = new Point(offsetX + 2 * space , offsetY + 3 * space);
points[2][2] = new Point(offsetX + 3 * space , offsetY + 3 * space);
inited = true; //初始化完成
}
public interface OnDrawFinishedListener{
boolean OnDrawFinished(List<integer> passList);
}
public void setOnDrawFinishedListener(OnDrawFinishedListener listener){
this.listener = listener;
}
}
</integer></integer></integer></point></point></span>
设置密码:
<span style="font-size:14px;">package com.jikexueyuan.screenlock;
import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.List;
public class SettingActivity extends ActionBarActivity {
List<integer> passList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_setting);
final GestureLock lock = (GestureLock)findViewById(R.id.LockView);
Button btn_reset = (Button)findViewById(R.id.btn_reset);
Button btn_save = (Button)findViewById(R.id.btn_save);
lock.setOnDrawFinishedListener(new GestureLock.OnDrawFinishedListener() {
@Override
public boolean OnDrawFinished(List<integer> passList) {
if (passList.size() < 3)
{
Toast.makeText(SettingActivity.this, 密码不能少于3个点, Toast.LENGTH_SHORT).show();
return false;
}
else {
SettingActivity.this.passList = passList;
return true;
}
}
});
btn_reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
lock.resetPoints();
}
});
btn_save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (passList != null)
{
StringBuilder sb = new StringBuilder();
for (Integer i : passList)
{
sb.append(i);
}
SharedPreferences sp = SettingActivity.this.getSharedPreferences(password, SettingActivity.this.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(password, sb.toString());
editor.commit();
Toast.makeText(SettingActivity.this, 保存完成, Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_setting, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
</integer></integer></span>
检验密码:
package com.example.patternlock;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Toast;
import java.util.List;
import com.example.patternlock.LockView.OnDrawFinishedListener;
public class LockActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lock);
SharedPreferences sp = getSharedPreferences(password, this.MODE_PRIVATE);
final String password = sp.getString(password, );
LockView lock = (LockView)findViewById(R.id.LockView);
lock.setOnDrawFinishedListener(new OnDrawFinishedListener() {
@Override
public boolean OnDrawFinished(List<integer> passList) {
StringBuilder sb = new StringBuilder();
for (Integer i : passList)
{
sb.append(i);
}
if (sb.toString().equals(password)){
Toast.makeText(LockActivity.this, 正确, Toast.LENGTH_SHORT).show();
return true;
}
else
{
Toast.makeText(LockActivity.this, 错误, Toast.LENGTH_SHORT).show();
return false;
}
}
});
}
}
</integer>