android利用paint 实现手势解锁

1、自定义view

package com.android.view;


import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;


public class GestureLockView extends View {
// 设置
private static final String SETTING = "setting";


private Paint paintNormal;
private Paint paintOnTouch;
private Paint paintInnerCycle;
private Paint paintLines;
private Paint paintKeyError;
private MyCycle[] cycles;
private Path linePath = new Path();
private List<Integer> linedCycles = new ArrayList<Integer>();
private OnGestureFinishListener onGestureFinishListener;
private String key;
private int eventX, eventY;
private boolean canContinue = true;


private boolean clean = false;


public boolean isCanContinue() {
return canContinue;
}


public void setClean(boolean clean) {
this.clean = clean;
if (clean == true) {
Log.e("Cat", "clean========="+clean);
timer = new Timer();
// 设置1s后清除
timer.schedule(new TimerTask() {
@Override
public void run() {
// 还原
eventX = eventY = 0;


for (int i = 0; i < cycles.length; i++) {
// 设置所有坐标不可点击
cycles[i].setOnTouch(false);
}


linedCycles.clear();// 清空集合
linePath.reset();// 清除所有的path的设置
canContinue = true;
postInvalidate();
}
}, 500);
}
}


private boolean result;
private Timer timer;


private int count = 0;


private int OUT_CYCLE_NORMAL = Color.rgb(108, 119, 138); // 正常外圆颜色
private int OUT_CYCLE_ONTOUCH = Color.rgb(007, 153, 192); // 选中外圆颜色
private int INNER_CYCLE_ONTOUCH = Color.rgb(007, 153, 192); // 选择内圆颜色
private int LINE_COLOR = Color.argb(127, 002, 210, 255); // 连接线颜色
private int ERROR_COLOR = Color.argb(127, 255, 000, 000); // 连接错误醒目提示颜色


public void setOnGestureFinishListener(OnGestureFinishListener onGestureFinishListener) {
this.onGestureFinishListener = onGestureFinishListener;
}


public void setKey(String key) {
this.key = key;
}


public void setResult(boolean bl) {
this.result = bl;
}


// 接口
public interface OnGestureFinishListener {
public void OnGestureFinish(boolean result);


public void OnSettingFinish(String result);
}


public GestureLockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}


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


public GestureLockView(Context context) {
super(context);
init();
}


/**
* 设定为设置模式

* @param b
*            为true则为设置模式
*/
public void setIsSetting(boolean b) {
if (b) {
this.key = SETTING;
}
}


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}


@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int perSize = 0;
if (cycles == null && (perSize = getWidth() / 6) > 0) {
cycles = new MyCycle[9];
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
MyCycle cycle = new MyCycle();
cycle.setPerSize(perSize);
cycle.setX(j);
cycle.setY(i);
// 设置圆圈大小和个数
cycle.setR(perSize * 0.7f);
cycles[i * 3 + j] = cycle;
}
}
}
}


private void init() {
paintNormal = new Paint();
paintNormal.setAntiAlias(true);
paintNormal.setStrokeWidth(3);
// 空心
paintNormal.setStyle(Paint.Style.STROKE);


paintOnTouch = new Paint();
paintOnTouch.setAntiAlias(true);
paintOnTouch.setStrokeWidth(3);
// 实心
paintOnTouch.setStyle(Paint.Style.FILL);


paintInnerCycle = new Paint();
paintInnerCycle.setAntiAlias(true);
paintInnerCycle.setStyle(Paint.Style.FILL);


paintLines = new Paint();
paintLines.setAntiAlias(true);
paintLines.setStyle(Paint.Style.STROKE);
paintLines.setStrokeWidth(6);


paintKeyError = new Paint();
paintKeyError.setAntiAlias(true);
paintKeyError.setStyle(Paint.Style.STROKE);
paintKeyError.setStrokeWidth(3);
}


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < cycles.length; i++) {


if (!canContinue && !result) {
// 输入错误的时候,显示红色
paintOnTouch.setColor(ERROR_COLOR);
paintInnerCycle.setColor(ERROR_COLOR);
paintLines.setColor(ERROR_COLOR);


} else if (cycles[i].isOnTouch()) {
paintOnTouch.setColor(OUT_CYCLE_ONTOUCH);
paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH);
paintLines.setColor(LINE_COLOR);
} else {
paintNormal.setColor(OUT_CYCLE_NORMAL);
paintInnerCycle.setColor(INNER_CYCLE_ONTOUCH);
paintLines.setColor(LINE_COLOR);
}
if (cycles[i].isOnTouch()) {
canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintOnTouch);
drawInnerBlueCycle(cycles[i], canvas);
} else {
canvas.drawCircle(cycles[i].getOx(), cycles[i].getOy(), cycles[i].getR(), paintNormal);
}
}
drawLine(canvas);
}


private void drawLine(Canvas canvas) {
linePath.reset();
if (linedCycles.size() > 0) {
for (int i = 0; i < linedCycles.size(); i++) {
int index = linedCycles.get(i);
float x = cycles[index].getOx();
float y = cycles[index].getOy();
if (i == 0) {
linePath.moveTo(x, y);
} else {
linePath.lineTo(x, y);
}
}
if (canContinue) {
linePath.lineTo(eventX, eventY);
} else {
linePath.lineTo(cycles[linedCycles.get(linedCycles.size() - 1)].getOx(),
cycles[linedCycles.get(linedCycles.size() - 1)].getOy());
}
canvas.drawPath(linePath, paintLines);
}
}


private void drawInnerBlueCycle(MyCycle myCycle, Canvas canvas) {
canvas.drawCircle(myCycle.getOx(), myCycle.getOy(), myCycle.getR() / 3, paintInnerCycle);
}


@Override
public boolean onTouchEvent(MotionEvent event) {
if (!canContinue) {
return true;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE: {
eventX = (int) event.getX();
eventY = (int) event.getY();
for (int i = 0; i < cycles.length; i++) {
if (!cycles[i].isPointIn(eventX, eventY)) {
// 如果按下的坐标不在 范围内就不执行下面的代码
continue;
}
// 设置选中
cycles[i].setOnTouch(true);


if (linedCycles.contains(cycles[i].getNum())) {
// 如果集合中有该坐标就跳过吗,不执行下面的代码
continue;
}
// 防止滑动是跳过中间点,路径上的加入已连接的列表并设置为已选择
if (linedCycles.size() != 0) {
MyCycle lastCycle = cycles[linedCycles.get(linedCycles.size() - 1)];
int num = (cycles[i].getX() - lastCycle.getX()) * (cycles[i].getX() - lastCycle.getX())
+ (cycles[i].getY() - lastCycle.getY()) * (cycles[i].getY() - lastCycle.getY());
if (num == 8 || num == 4) {
cycles[(lastCycle.getNum() + cycles[i].getNum()) / 2].setOnTouch(true);
linedCycles.add(cycles[(lastCycle.getNum() + cycles[i].getNum()) / 2].getNum());
}
}
linedCycles.add(cycles[i].getNum());
// Log.e("Cat",
// "linedCycles.size============"+linedCycles.size());
// Log.e("Cat",
// "linedCycles.get(i)============"+linedCycles.get(i));
}
break;
}
case MotionEvent.ACTION_UP: {
// 暂停触碰
canContinue = false;
// 检查结果
StringBuffer sb = new StringBuffer();
for (int i = 0; i < linedCycles.size(); i++) {
sb.append(linedCycles.get(i));
}
result = sb.toString().equals(key);


// 接口不是空的时候进入
if (onGestureFinishListener != null) {
// 不是设置的时候进入
if (!SETTING.equals(key)) {
Log.e("Cat", "result================" + result);


if (result == false) {
count++;
}
onGestureFinishListener.OnGestureFinish(result);
timer = new Timer();
// 设置1s后清除
timer.schedule(new TimerTask() {
@Override
public void run() {
// 还原
eventX = eventY = 0;


for (int i = 0; i < cycles.length; i++) {
// 设置所有坐标不可点击
cycles[i].setOnTouch(false);
}


linedCycles.clear();// 清空集合
linePath.reset();// 清除所有的path的设置
canContinue = true;
// 设置输入错误就锁定30s
if (count >= 5) {
canContinue = false;
}


postInvalidate();
}
}, 1000);
} else {
// 设置的时候 调用接口,传值
onGestureFinishListener.OnSettingFinish(sb.toString());
result = true;
}
}
}
break;
}
invalidate();
return true;
}
}

2、MyCycle类对坐标进行计算

package com.android.view;


public class MyCycle {
private float r;         // 半径长度
private int x; //简略坐标
private int y; //简略坐标
private int perSize; //坐标系数
private boolean onTouch; // false=未选中
public float getR() {
return r;
}
public void setR(float r) {
this.r = r;
}
public boolean isOnTouch() {
return onTouch;
}
public void setOnTouch(boolean onTouch) {
this.onTouch = onTouch;
}
public boolean isPointIn(int x, int y) {
double distance = Math.sqrt((x - this.getOx()) * (x - this.getOx()) + (y - this.getOy()) * (y - this.getOy()));
return distance < r;
}
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;
}

public int getPerSize() {
return perSize;
}
public void setPerSize(int perSize) {
this.perSize = perSize;
}


//获取实际x坐标
public int getOx() {
return perSize * (x * 2 + 1);
}
//获取实际y坐标
public int getOy() {
return perSize * (y * 2 + 1);
}

// 第y行 第x列 的编号
public int getNum() {
return (3 * this.y + this.x);
}
}

xml布局文件

使用自定义的view

    <com.android.view.GestureLockView
        android:id="@+id/gv"
        android:layout_marginLeft="40dp"
        android:layout_marginRight="40dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/imageview1"
        android:background="#0000" />

在main中使用

package com.android.gesturelock;


import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.Toast;


import com.android.view.GestureLockView;
import com.android.view.GestureLockView.OnGestureFinishListener;
import com.example.gesturelock.R;


public class MainActivity extends Activity implements OnClickListener{
GestureLockView gv;
Button btnChange;
String pwd = null;
int count=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnChange = (Button) findViewById(R.id.btnChangePwd);
btnChange.setOnClickListener(this);
SharedPreferences sp = this.getSharedPreferences("config", MODE_PRIVATE);
gv = (GestureLockView) findViewById(R.id.gv);
if(sp != null){
pwd = sp.getString("pwd", null);
}
gv.setOnGestureFinishListener(new OnGestureFinishListener() {


@Override
public void OnGestureFinish(boolean result) {
if(pwd == null){
Toast.makeText(MainActivity.this, "未检测到密码,请先设置",
Toast.LENGTH_SHORT).show();
return;
}
if(result){
Toast.makeText(MainActivity.this, "验证成功!",
Toast.LENGTH_SHORT).show();
}else{
count++;

Toast.makeText(MainActivity.this, "验证失败!",
Toast.LENGTH_SHORT).show();
}
}


@Override
public void OnSettingFinish(String result) {
// TODO Auto-generated method stub

}
});


}
@Override
protected void onResume() {
SharedPreferences sp = this.getSharedPreferences("config", MODE_PRIVATE);
gv = (GestureLockView) findViewById(R.id.gv);
if(sp != null){
pwd = sp.getString("pwd", null);
}
gv.setKey(pwd); 
super.onResume();
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnChangePwd:
Intent intent = new Intent(this, ChangePwd.class);
startActivity(intent);
break;


default:
break;
}
}
}


代码中很多注释,很好看懂



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值