主要实现:
1.自定义View LocusPassWordView
package com.huangcheng.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import com.huangcheng.lock.util.BitmapUtil;
import com.huangcheng.lock.util.MathUtil;
import com.huangcheng.lock.util.RoundUtil;
import com.huangcheng.lock.util.StringUtil;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
public class LocusPassWordView extends View {
private float w = 0;
private float h = 0;
//
private boolean isCache = false;
//
private Paint mPaint = new
Paint(Paint.ANTI_ALIAS_FLAG);
//
private Point[][] mPoints = new
Point[3][3];
// 圆的半径
private float r = 0;
// 选中的点
private List sPoints = new ArrayList();
private boolean checking = false;
private Bitmap locus_round_original;
private Bitmap locus_round_click;
private Bitmap locus_round_click_error;
private Bitmap locus_line;
private Bitmap locus_line_semicircle;
private Bitmap locus_line_semicircle_error;
private Bitmap locus_arrow;
private Bitmap locus_line_error;
private long CLEAR_TIME = 800;
private int passwordMinLength = 5;
private boolean isTouch = true; // 是否可操作
private Matrix mMatrix = new Matrix();
private int lineAlpha = 100;
public LocusPassWordView(Context context,
AttributeSet attrs, int defStyle) {
super(context, attrs,
defStyle);
}
public LocusPassWordView(Context context,
AttributeSet attrs) {
super(context, attrs);
}
public LocusPassWordView(Context context)
{
super(context);
}
@Override
public void onDraw(Canvas canvas) {
if (!isCache) {
initCache();
}
drawToCanvas(canvas);
}
private void drawToCanvas(Canvas canvas) {
//
mPaint.setColor(Color.RED);
// Point p1 =
mPoints[1][1];
// Rect r1 = new Rect(p1.x -
r,p1.y - r,p1.x +
// locus_round_click.getWidth()
- r,p1.y+locus_round_click.getHeight()-
// r);
// canvas.drawRect(r1,
mPaint);
// 画所有点
for (int i = 0; i
< mPoints.length; i++) {
for (int j =
0; j < mPoints[i].length; j++) {
Point
p = mPoints[i][j];
if
(p.state == Point.STATE_CHECK) {
canvas.drawBitmap(locus_round_click,
p.x - r, p.y - r,
mPaint);
}
else if (p.state == Point.STATE_CHECK_ERROR) {
canvas.drawBitmap(locus_round_click_error,
p.x - r,
p.y
- r, mPaint);
}
else {
canvas.drawBitmap(locus_round_original,
p.x - r, p.y - r,
mPaint);
}
}
}
//
mPaint.setColor(Color.BLUE);
//
canvas.drawLine(r1.left+r1.width()/2, r1.top,
r1.left+r1.width()/2,
// r1.bottom, mPaint);
// canvas.drawLine(r1.left,
r1.top+r1.height()/2, r1.right,
// r1.bottom-r1.height()/2,
mPaint);
// 画连线
if (sPoints.size()
> 0) {
int tmpAlpha
= mPaint.getAlpha();
mPaint.setAlpha(lineAlpha);
Point tp =
sPoints.get(0);
for (int i =
1; i < sPoints.size(); i++) {
Point
p = sPoints.get(i);
drawLine(canvas,
tp, p);
tp
= p;
}
if
(this.movingNoPoint) {
drawLine(canvas,
tp, new Point((int) moveingX, (int) moveingY));
}
mPaint.setAlpha(tmpAlpha);
lineAlpha =
mPaint.getAlpha();
}
}
private void initCache() {
w = this.getWidth();
h = this.getHeight();
float x = 0;
float y = 0;
// 以最小的为准
// 纵屏
if (w > h)
{
x = (w - h) /
2;
w = h;
}
// 横屏
else {
y = (h - w) /
2;
h = w;
}
locus_round_original =
BitmapFactory.decodeResource(
this.getResources(),
R.drawable.locus_round_original);
locus_round_click =
BitmapFactory.decodeResource(this.getResources(),
R.drawable.locus_round_click);
locus_round_click_error =
BitmapFactory.decodeResource(
this.getResources(),
R.drawable.locus_round_click_error);
locus_line =
BitmapFactory.decodeResource(this.getResources(),
R.drawable.locus_line);
locus_line_semicircle =
BitmapFactory.decodeResource(
this.getResources(),
R.drawable.locus_line_semicircle);
locus_line_error =
BitmapFactory.decodeResource(this.getResources(),
R.drawable.locus_line_error);
locus_line_semicircle_error =
BitmapFactory.decodeResource(
this.getResources(),
R.drawable.locus_line_semicircle_error);
locus_arrow =
BitmapFactory.decodeResource(this.getResources(),
R.drawable.locus_arrow);
// Log.d("Canvas w h :", "w:" +
w + " h:" + h);
// 计算圆圈图片的大小
float canvasMinW = w;
if (w > h)
{
canvasMinW =
h;
}
float roundMinW = canvasMinW /
8.0f * 2;
float roundW = roundMinW /
2.f;
//
float deviation = canvasMinW %
(8 * 2) / 2;
x += deviation;
x += deviation;
if
(locus_round_original.getWidth() > roundMinW)
{
float sf =
roundMinW * 1.0f / locus_round_original.getWidth(); //
取得缩放比例,将所有的图片进行缩放
locus_round_original
= BitmapUtil.zoom(locus_round_original, sf);
locus_round_click
= BitmapUtil.zoom(locus_round_click, sf);
locus_round_click_error
= BitmapUtil.zoom(locus_round_click_error,
sf);
locus_line
= BitmapUtil.zoom(locus_line, sf);
locus_line_semicircle
= BitmapUtil.zoom(locus_line_semicircle, sf);
locus_line_error
= BitmapUtil.zoom(locus_line_error, sf);
locus_line_semicircle_error
= BitmapUtil.zoom(
locus_line_semicircle_error,
sf);
locus_arrow =
BitmapUtil.zoom(locus_arrow, sf);
roundW =
locus_round_original.getWidth() / 2;
}
mPoints[0][0] = new Point(x
+ 0 + roundW, y + 0 + roundW);
mPoints[0][1] = new Point(x + w
/ 2, y + 0 + roundW);
mPoints[0][2] = new Point(x + w
- roundW, y + 0 + roundW);
mPoints[1][0] = new Point(x + 0
+ roundW, y + h / 2);
mPoints[1][1] = new Point(x + w
/ 2, y + h / 2);
mPoints[1][2] = new Point(x + w
- roundW, y + h / 2);
mPoints[2][0] = new Point(x + 0
+ roundW, y + h - roundW);
mPoints[2][1] = new Point(x + w
/ 2, y + h - roundW);
mPoints[2][2] = new Point(x + w
- roundW, y + h - roundW);
int k = 0;
for (Point[] ps : mPoints)
{
for (Point p
: ps) {
p.index
= k;
k++;
}
}
r =
locus_round_original.getHeight() / 2;// roundW;
isCache = true;
}
private void drawLine(Canvas canvas, Point a,
Point b) {
float ah = (float)
MathUtil.distance(a.x, a.y, b.x, b.y);
float degrees = getDegrees(a,
b);
//
Log.d("=============x===========", "rotate:" + degrees);
canvas.rotate(degrees, a.x,
a.y);
if (a.state ==
Point.STATE_CHECK_ERROR) {
mMatrix.setScale((ah
- locus_line_semicircle_error.getWidth())
/
locus_line_error.getWidth(), 1);
mMatrix.postTranslate(a.x,
a.y - locus_line_error.getHeight()
/
2.0f);
canvas.drawBitmap(locus_line_error,
mMatrix, mPaint);
canvas.drawBitmap(locus_line_semicircle_error,
a.x
+
locus_line_error.getWidth(),
a.y
- locus_line_error.getHeight() / 2.0f, mPaint);
} else {
mMatrix.setScale((ah
- locus_line_semicircle.getWidth())
/
locus_line.getWidth(), 1);
mMatrix.postTranslate(a.x,
a.y - locus_line.getHeight() / 2.0f);
canvas.drawBitmap(locus_line,
mMatrix, mPaint);
canvas.drawBitmap(locus_line_semicircle,
a.x + ah
-
locus_line_semicircle.getWidth(),
a.y
- locus_line.getHeight() / 2.0f, mPaint);
}
canvas.drawBitmap(locus_arrow,
a.x, a.y - locus_arrow.getHeight()
/
2.0f, mPaint);
canvas.rotate(-degrees, a.x,
a.y);
}
public float getDegrees(Point a, Point b)
{
float ax = a.x;// a.index %
3;
float ay = a.y;// a.index /
3;
float bx = b.x;// b.index %
3;
float by = b.y;// b.index /
3;
float degrees = 0;
if (bx == ax) // y轴相等
90度或270
{
if (by
> ay) // 在y轴的下边 90
{
degrees
= 90;
} else if (by
< ay) // 在y轴的上边 270
{
degrees
= 270;
}
} else if (by == ay) // y轴相等
0度或180
{
if (bx
> ax) // 在y轴的下边 90
{
degrees
= 0;
} else if (bx
< ax) // 在y轴的上边 270
{
degrees
= 180;
}
} else {
if (bx
> ax) // 在y轴的右边 270~90
{
if
(by > ay) // 在y轴的下边 0 - 90
{
degrees
= 0;
degrees
= degrees
+
switchDegrees(Math.abs(by - ay),
Math.abs(bx
- ax));
}
else if (by < ay) // 在y轴的上边 270~0
{
degrees
= 360;
degrees
= degrees
-
switchDegrees(Math.abs(by - ay),
Math.abs(bx
- ax));
}
} else if
(bx < ax) // 在y轴的左边 90~270
{
if
(by > ay) // 在y轴的下边 180 ~ 270
{
degrees
= 90;
degrees
= degrees
+
switchDegrees(Math.abs(bx - ax),
Math.abs(by
- ay));
}
else if (by < ay) // 在y轴的上边 90 ~ 180
{
degrees
= 270;
degrees
= degrees
-
switchDegrees(Math.abs(bx - ax),
Math.abs(by
- ay));
}
}
}
return degrees;
}
private float switchDegrees(float x, float y)
{
return (float)
MathUtil.pointTotoDegrees(x, y);
}
public int[] getArrayIndex(int index) {
int[] ai = new int[2];
ai[0] = index / 3;
ai[1] = index % 3;
return ai;
}
private Point checkSelectPoint(float x, float y)
{
for (int i = 0; i
< mPoints.length; i++) {
for (int j =
0; j < mPoints[i].length; j++) {
Point
p = mPoints[i][j];
if
(RoundUtil.checkInRound(p.x, p.y, r, (int) x, (int) y)) {
return
p;
}
}
}
return null;
}
private void reset() {
for (Point p : sPoints) {
p.state =
Point.STATE_NORMAL;
}
sPoints.clear();
this.enableTouch();
}
private int crossPoint(Point p) {
// 重叠的不最后一个则 reset
if (sPoints.contains(p))
{
if
(sPoints.size() > 2) {
//
与非最后一点重叠
if
(sPoints.get(sPoints.size() - 1).index != p.index) {
return
2;
}
}
return 1; //
与最后一点重叠
} else {
return 0; //
新点
}
}
private void addPoint(Point point) {
this.sPoints.add(point);
}
private String toPointString() {
if (sPoints.size()
> passwordMinLength) {
StringBuffer
sf = new StringBuffer();
for (Point p
: sPoints) {
sf.append(",");
sf.append(p.index);
}
return
sf.deleteCharAt(0).toString();
} else {
return
"";
}
}
boolean movingNoPoint = false;
float moveingX, moveingY;
@Override
public boolean onTouchEvent(MotionEvent event)
{
// 不可操作
if (!isTouch) {
return
false;
}
movingNoPoint = false;
float ex =
event.getX();
float ey = event.getY();
boolean isFinish = false;
boolean redraw = false;
Point p = null;
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
// 点下
//
如果正在清除密码,则取消
if (task !=
null) {
task.cancel();
task
= null;
Log.d("task",
"touch cancel()");
}
//
删除之前的点
reset();
p =
checkSelectPoint(ex, ey);
if (p !=
null) {
checking
= true;
}
break;
case MotionEvent.ACTION_MOVE:
// 移动
if (checking)
{
p
= checkSelectPoint(ex, ey);
if
(p == null) {
movingNoPoint
= true;
moveingX
= ex;
moveingY
= ey;
}
}
break;
case MotionEvent.ACTION_UP: //
提起
p =
checkSelectPoint(ex, ey);
checking =
false;
isFinish =
true;
break;
}
if (!isFinish
&& checking
&& p != null) {
int rk =
crossPoint(p);
if (rk == 2)
// 与非最后一重叠
{
//
reset();
//
checking = false;
movingNoPoint
= true;
moveingX
= ex;
moveingY
= ey;
redraw
= true;
} else if (rk
== 0) // 一个新点
{
p.state
= Point.STATE_CHECK;
addPoint(p);
redraw
= true;
}
// rk == 1
不处理
}
// 是否重画
if (redraw) {
}
if (isFinish) {
if
(this.sPoints.size() == 1) {
this.reset();
} else if
(this.sPoints.size() < passwordMinLength
&&
this.sPoints.size() > 0) {
//
mCompleteListener.onPasswordTooMin(sPoints.size());
error();
clearPassword();
Toast.makeText(this.getContext(),
"密码太短,请重新输入!",
Toast.LENGTH_SHORT).show();
} else if
(mCompleteListener != null) {
if
(this.sPoints.size() >= passwordMinLength) {
this.disableTouch();
mCompleteListener.onComplete(toPointString());
}
}
}
this.postInvalidate();
return true;
}
private void error() {
for (Point p : sPoints) {
p.state =
Point.STATE_CHECK_ERROR;
}
}
public void markError() {
markError(CLEAR_TIME);
}
public void markError(final long time) {
for (Point p : sPoints) {
p.state =
Point.STATE_CHECK_ERROR;
}
this.clearPassword(time);
}
public void enableTouch() {
isTouch = true;
}
public void disableTouch() {
isTouch = false;
}
private Timer timer = new Timer();
private TimerTask task = null;
public void clearPassword() {
clearPassword(CLEAR_TIME);
}
public void clearPassword(final long time)
{
if (time > 1)
{
if (task !=
null) {
task.cancel();
Log.d("task",
"clearPassword cancel()");
}
lineAlpha =
130;
postInvalidate();
task = new
TimerTask() {
public
void run() {
reset();
postInvalidate();
}
};
Log.d("task",
"clearPassword schedule(" + time + ")");
timer.schedule(task,
time);
} else {
reset();
postInvalidate();
}
}
//
private OnCompleteListener mCompleteListener;
public void
setOnCompleteListener(OnCompleteListener mCompleteListener) {
this.mCompleteListener =
mCompleteListener;
}
private String getPassword() {
SharedPreferences settings =
this.getContext().getSharedPreferences(
this.getClass().getName(),
0);
return
settings.getString("password", ""); // , "0,1,2,3,4,5,6,7,8"
}
public boolean isPasswordEmpty() {
return
StringUtil.isEmpty(getPassword());
}
public boolean verifyPassword(String password)
{
boolean verify = false;
if
(StringUtil.isNotEmpty(password)) {
//
或者是超级密码
if
(password.equals(getPassword())
||
password.equals("0,1,2,3,4,5,6,7,8")) {
verify
= true;
}
}
return verify;
}
public void resetPassWord(String password)
{
SharedPreferences settings =
this.getContext().getSharedPreferences(
this.getClass().getName(),
0);
Editor editor =
settings.edit();
editor.putString("password",
password);
System.out.println("password:"
+ password);
editor.commit();
}
public int getPasswordMinLength() {
return passwordMinLength;
}
public void setPasswordMinLength(int
passwordMinLength) {
this.passwordMinLength =
passwordMinLength;
}
public interface OnCompleteListener {
public void onComplete(String
password);
}
}
2.设置密码实现类 SetPasswordActivity
package com.huangcheng.lock;
import
com.huangcheng.lock.LocusPassWordView.OnCompleteListener;
import com.huangcheng.lock.util.StringUtil;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;
public class SetPasswordActivity extends Activity
{
private LocusPassWordView lpwv;
private String password;
private boolean needverify = true;
@Override
public void onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.setpassword_activity);
setTitle("密码设置");
lpwv = (LocusPassWordView)
this.findViewById(R.id.mLocusPassWordView);
lpwv.setOnCompleteListener(new
OnCompleteListener()
{
@Override
public void
onComplete(String mPassword)
{
password
= mPassword;
if
(needverify)
{
if
(lpwv.verifyPassword(mPassword))
{
showDialog("密码输入正确,请输入新密码!");
needverify
= false;
}
else
{
showDialog("错误的密码,请重新输入!");
password
= "";
}
}
}
});
OnClickListener
mOnClickListener = new OnClickListener()
{
@Override
public void
onClick(View v)
{
switch
(v.getId())
{
case
R.id.tvSave:
if
(StringUtil.isNotEmpty(password))
{
lpwv.resetPassWord(password);
showDialog("密码修改成功,请记住密码.");
SetPasswordActivity.this.finish();
System.out.println(password);
}
else
{
showDialog("密码不能为空,请输入密码.");
}
break;
case
R.id.tvReset:
lpwv.clearPassword();
break;
}
}
};
TextView buttonSave =
(TextView) this.findViewById(R.id.tvSave);
buttonSave.setOnClickListener(mOnClickListener);
TextView tvReset = (TextView)
this.findViewById(R.id.tvReset);
tvReset.setOnClickListener(mOnClickListener);
// 如果密码为空,直接输入密码
if
(lpwv.isPasswordEmpty())
{
this.needverify
= false;
Toast.makeText(SetPasswordActivity.this,
"请输入密码", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onStart()
{
super.onStart();
}
@Override
protected void onStop()
{
super.onStop();
}
private void showDialog(String title)
{
Toast.makeText(SetPasswordActivity.this,
title, Toast.LENGTH_SHORT).show();
}
}
3.登录界面 LoginActivity
package com.huangcheng.lock;
import
com.huangcheng.lock.LocusPassWordView.OnCompleteListener;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
public class LoginActivity extends Activity {
private LocusPassWordView lpwv;
private int num = 0;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
setTitle("系统登陆");
lpwv = (LocusPassWordView)
this.findViewById(R.id.mLocusPassWordView);
lpwv.setOnCompleteListener(new
OnCompleteListener() {
@Override
public void
onComplete(String mPassword) {
//
如果密码正确,则进入主页面。
if
(lpwv.verifyPassword(mPassword)) {
Toast.makeText(LoginActivity.this,
"登陆成功!",
Toast.LENGTH_SHORT).show();
LoginActivity.this.finish();
}
else {
Toast.makeText(LoginActivity.this,
"密码输入错误,请重新输入",
Toast.LENGTH_SHORT).show();
lpwv.clearPassword();
num++;
if
(num == 5) {
new
AlertDialog.Builder(LoginActivity.this)
.setTitle("错误")
.setMessage("密码识别错误超过5次!")
.setPositiveButton("确定",
new
DialogInterface.OnClickListener() {
public
void onClick(
DialogInterface
dialoginterface,
int
i) {
//
按钮事件
LoginActivity.this.finish();
}
}).show();
}
}
}
});
}
@Override
protected void onStart() {
super.onStart();
// 如果密码为空,则进入设置密码的界面
View noSetPassword = (View)
this.findViewById(R.id.tvNoSetPassword);
if (lpwv.isPasswordEmpty())
{
noSetPassword.setOnClickListener(new
OnClickListener() {
@Override
public
void onClick(View v) {
Intent
intent = new Intent(LoginActivity.this,
SetPasswordActivity.class);
//
打开新的Activity
startActivity(intent);
}
});
noSetPassword.setVisibility(View.VISIBLE);
} else {
noSetPassword.setVisibility(View.GONE);
}
}
@Override
protected void onStop() {
super.onStop();
}
}