招财进宝手势锁,Android手势密码的实现
Posted wulianghuan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了招财进宝手势锁,Android手势密码的实现相关的知识,希望对你有一定的参考价值。
这几个月都是在做招财进宝项目,招财进宝是盛大网络旗下,盛付通支付服务有限公司最新推出的,一款高收益低风险的理财APP,有兴趣的可以下载玩玩,收益不错哦!!!
招财进宝下载地址:http://8.shengpay.com/
前段时间因产品需求,做了一个手势密码,跟支付宝的手势密码类似,这里跟大家分享交流一下我实现的方式吧。
这篇来分享一下绘制手势密码的实现(主要是设置手势密码、校验手势密码):
一、大致界面介绍:
图1 图2
图3 图4
图1:手势密码绘制界面 【主要是绘制上方的9个提示图标和9个宫格密码图标】
图2:设置手势密码 【监听手势的输入,TouchEvent的事件处理,获取输入的手势密码,同时显示在上方的提示区域】
图3:再绘制一次,两次密码不一致提示界面 【这里在实现的时候,错误提示文字加了“左右晃动的动画”,错误路径颜色标记为红色】
图4:校验手势密码,输入的密码错误,给予红色路径+错误文字提示
二、实现思路:
1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标;
2. 手势密码绘制区域,用一个类(GestureContentView.java)来实现,它继承自ViewGroup里面, 添加9个ImageView来表示图标, 在onLayout()方法中设置它们的位置;
3. 手势路径绘制, 用一个类(GestureDrawline.java)来实现,复写onTouchEvent()方法,在这个方法里面监听TouchEvent事件: ACTION_DOWN、ACTION_MOVE、ACTION_UP事件,来绘制手势连接不同点之间的路径;
4. 9个点的对象,用一个类(GesturePoint.java)来实现,保存它的位置、状态、背景图片等相关信息;
5. 手势密码的获取,判断手指当前的位置,根据滑动路径经过的点,按顺序保存绘制的点的顺序(这里的点顺序从上到下分别是:1,2,3,4,5,6,7,8,9),不能有重复的点。
三、代码实现步骤:
1.要用一个类来表示这9个点中的第一个点。里面保留有当前点的上下左右的各个位置等属性
2.自定义GroupView,用来装9个点,9个点的显示是通过ImageView。复写onLayout这个方法,让点按需求排列
3.定义一个可以画线的View,复写onTouchEvent方法,在这个方法里面进行画直线的操作
4.判断用户手指当前的位置,取出当前的位置去与那9个点中的每个点的位置进行比较,如果用户点的位置在某一个点之内,那么当那个点置换背景图片。
具体实现代码如下:
1. LockIndicator.java 图案提示类
package com.snda.fund.widget;
import com.snda.fund.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
*
* 手势密码图案提示
* @author wulianghuan
*
*/
public class LockIndicator extends View
private int numRow = 3; // 行
private int numColum = 3; // 列
private int patternWidth = 40;
private int patternHeight = 40;
private int f = 5;
private int g = 5;
private int strokeWidth = 3;
private Paint paint = null;
private Drawable patternNoraml = null;
private Drawable patternPressed = null;
private String lockPassStr; // 手势密码
public LockIndicator(Context paramContext)
super(paramContext);
public LockIndicator(Context paramContext, AttributeSet paramAttributeSet)
super(paramContext, paramAttributeSet, 0);
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(strokeWidth);
paint.setStyle(Paint.Style.STROKE);
patternNoraml = getResources().getDrawable(R.drawable.lock_pattern_node_normal);
patternPressed = getResources().getDrawable(R.drawable.lock_pattern_node_pressed);
if (patternPressed != null)
patternWidth = patternPressed.getIntrinsicWidth();
patternHeight = patternPressed.getIntrinsicHeight();
this.f = (patternWidth / 4);
this.g = (patternHeight / 4);
patternPressed.setBounds(0, 0, patternWidth, patternHeight);
patternNoraml.setBounds(0, 0, patternWidth, patternHeight);
@Override
protected void onDraw(Canvas canvas)
if ((patternPressed == null) || (patternNoraml == null))
return;
// 绘制3*3的图标
for (int i = 0; i < numRow; i++)
for (int j = 0; j < numColum; j++)
paint.setColor(-16777216);
int i1 = j * patternHeight + j * this.g;
int i2 = i * patternWidth + i * this.f;
canvas.save();
canvas.translate(i1, i2);
String curNum = String.valueOf(numColum * i + (j + 1));
if (!TextUtils.isEmpty(lockPassStr))
if (lockPassStr.indexOf(curNum) == -1)
// 未选中
patternNoraml.draw(canvas);
else
// 被选中
patternPressed.draw(canvas);
else
// 重置状态
patternNoraml.draw(canvas);
canvas.restore();
@Override
protected void onMeasure(int paramInt1, int paramInt2)
if (patternPressed != null)
setMeasuredDimension(numColum * patternHeight + this.g
* (-1 + numColum), numRow * patternWidth + this.f
* (-1 + numRow));
/**
* 请求重新绘制
* @param paramString 手势密码字符序列
*/
public void setPath(String paramString)
lockPassStr = paramString;
invalidate();
2. GestureContentView.java 手势密码容器类
它继承ViewGroup,通过addView()方法添加子viewe,手势密码的9个输入点(GesturePoint)、GestureDrawline手势密码路径都放在这个容器当中,下面是它的具体实现方法:
package com.wujay.fund.widget;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.wujay.fund.R;
import com.wujay.fund.common.AppUtil;
import com.wujay.fund.entity.GesturePoint;
import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
/**
* 手势密码容器类
*
*/
public class GestureContentView extends ViewGroup
private int baseNum = 6;
private int[] screenDispaly;
/**
* 每个点区域的宽度
*/
private int blockWidth;
/**
* 声明一个集合用来封装坐标集合
*/
private List<GesturePoint> list;
private Context context;
private boolean isVerify;
private GestureDrawline gestureDrawline;
/**
* 包含9个ImageView的容器,初始化
* @param context
* @param isVerify 是否为校验手势密码
* @param passWord 用户传入密码
* @param callBack 手势绘制完毕的回调
*/
public GestureContentView(Context context, boolean isVerify, String passWord, GestureCallBack callBack)
super(context);
screenDispaly = AppUtil.getScreenDispaly(context);
blockWidth = screenDispaly[0]/3;
this.list = new ArrayList<GesturePoint>();
this.context = context;
this.isVerify = isVerify;
// 添加9个图标
addChild();
// 初始化一个可以画线的view
gestureDrawline = new GestureDrawline(context, list, isVerify, passWord, callBack);
private void addChild()
for (int i = 0; i < 9; i++)
ImageView image = new ImageView(context);
image.setBackgroundResource(R.drawable.gesture_node_normal);
this.addView(image);
invalidate();
// 第几行
int row = i / 3;
// 第几列
int col = i % 3;
// 定义点的每个属性
int leftX = col*blockWidth+blockWidth/baseNum;
int topY = row*blockWidth+blockWidth/baseNum;
int rightX = col*blockWidth+blockWidth-blockWidth/baseNum;
int bottomY = row*blockWidth+blockWidth-blockWidth/baseNum;
GesturePoint p = new GesturePoint(leftX, rightX, topY, bottomY, image,i+1);
this.list.add(p);
public void setParentView(ViewGroup parent)
// 得到屏幕的宽度
int width = screenDispaly[0];
LayoutParams layoutParams = new LayoutParams(width, width);
this.setLayoutParams(layoutParams);
gestureDrawline.setLayoutParams(layoutParams);
parent.addView(gestureDrawline);
parent.addView(this);
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
for (int i = 0; i < getChildCount(); i++)
//第几行
int row = i/3;
//第几列
int col = i%3;
View v = getChildAt(i);
v.layout(col*blockWidth+blockWidth/baseNum, row*blockWidth+blockWidth/baseNum,
col*blockWidth+blockWidth-blockWidth/baseNum, row*blockWidth+blockWidth-blockWidth/baseNum);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 遍历设置每个子view的大小
for (int i = 0; i < getChildCount(); i++)
View v = getChildAt(i);
v.measure(widthMeasureSpec, heightMeasureSpec);
/**
* 保留路径delayTime时间长
* @param delayTime
*/
public void clearDrawlineState(long delayTime)
gestureDrawline.clearDrawlineState(delayTime);
3. GestureDrawline.java 手势密码路径绘制类
根据OnTouchEvent方法的不同事件,ACTION_DOWN、ACTION_MOVE、ACTION_UP分别处理不同的逻辑。
package com.wujay.fund.widget;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.wujay.fund.common.AppUtil;
import com.wujay.fund.common.Constants;
import com.wujay.fund.entity.GesturePoint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.PorterDuff;
import android.os.Handler;
import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
/**
* 手势密码路径绘制
*
*/
public class GestureDrawline extends View
private int mov_x;// 声明起点坐标
private int mov_y;
private Paint paint;// 声明画笔
private Canvas canvas;// 画布
private Bitmap bitmap;// 位图
private List<GesturePoint> list;// 装有各个view坐标的集合
private List<Pair<GesturePoint, GesturePoint>> lineList;// 记录画过的线
private Map<String, GesturePoint> autoCheckPointMap;// 自动选中的情况点
private boolean isDrawEnable = true; // 是否允许绘制
/**
* 屏幕的宽度和高度
*/
private int[] screenDispaly;
/**
* 手指当前在哪个Point内
*/
private GesturePoint currentPoint;
/**
* 用户绘图的回调
*/
private GestureCallBack callBack;
/**
* 用户当前绘制的图形密码
*/
private StringBuilder passWordSb;
/**
* 是否为校验
*/
private boolean isVerify;
/**
* 用户传入的passWord
*/
private String passWord;
public GestureDrawline(Context context, List<GesturePoint> list, boolean isVerify,
String passWord, GestureCallBack callBack)
super(context);
screenDispaly = AppUtil.getScreenDispaly(context);
paint = new Paint(Paint.DITHER_FLAG);// 创建一个画笔
bitmap = Bitmap.createBitmap(screenDispaly[0], screenDispaly[0], Bitmap.Config.ARGB_8888); // 设置位图的宽高
canvas = new Canvas();
canvas.setBitmap(bitmap);
paint.setStyle(Style.STROKE);// 设置非填充
paint.setStrokeWidth(10);// 笔宽5像素
paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
paint.setAntiAlias(true);// 不显示锯齿
this.list = list;
this.lineList = new ArrayList<Pair<GesturePoint, GesturePoint>>();
initAutoCheckPointMap();
this.callBack = callBack;
// 初始化密码缓存
this.isVerify = isVerify;
this.passWordSb = new StringBuilder();
this.passWord = passWord;
private void initAutoCheckPointMap()
autoCheckPointMap = new HashMap<String,GesturePoint>();
autoCheckPointMap.put("1,3", getGesturePointByNum(2));
autoCheckPointMap.put("1,7", getGesturePointByNum(4));
autoCheckPointMap.put("1,9", getGesturePointByNum(5));
autoCheckPointMap.put("2,8", getGesturePointByNum(5));
autoCheckPointMap.put("3,7", getGesturePointByNum(5));
autoCheckPointMap.put("3,9", getGesturePointByNum(6));
autoCheckPointMap.put("4,6", getGesturePointByNum(5));
autoCheckPointMap.put("7,9", getGesturePointByNum(8));
private GesturePoint getGesturePointByNum(int num)
for (GesturePoint point : list)
if (point.getNum() == num)
return point;
return null;
// 画位图
@Override
protected void onDraw(Canvas canvas)
// super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null);
// 触摸事件
@Override
public boolean onTouchEvent(MotionEvent event)
if (isDrawEnable == false)
// 当期不允许绘制
return true;
paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
mov_x = (int) event.getX();
mov_y = (int) event.getY();
// 判断当前点击的位置是处于哪个点之内
currentPoint = getPointAt(mov_x, mov_y);
if (currentPoint != null)
currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
passWordSb.append(currentPoint.getNum());
// canvas.drawPoint(mov_x, mov_y, paint);// 画点
invalidate();
break;
case MotionEvent.ACTION_MOVE:
clearScreenAndDrawList();
// 得到当前移动位置是处于哪个点内
GesturePoint pointAt = getPointAt((int) event.getX(), (int) event.getY());
// 代表当前用户手指处于点与点之前
if (currentPoint == null && pointAt == null)
return true;
else // 代表用户的手指移动到了点上
if (currentPoint == null) // 先判断当前的point是不是为null
// 如果为空,那么把手指移动到的点赋值给currentPoint
currentPoint = pointAt;
// 把currentPoint这个点设置选中为true;
currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
passWordSb.append(currentPoint.getNum());
if (pointAt == null || currentPoint.equals(pointAt) || Constants.POINT_STATE_SELECTED == pointAt.getPointState())
// 点击移动区域不在圆的区域,或者当前点击的点与当前移动到的点的位置相同,或者当前点击的点处于选中状态
// 那么以当前的点中心为起点,以手指移动位置为终点画线
canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), event.getX(), event.getY(), paint);// 画线
else
// 如果当前点击的点与当前移动到的点的位置不同
// 那么以前前点的中心为起点,以手移动到的点的位置画线
canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), pointAt.getCenterX(), pointAt.getCenterY(), paint);// 画线
pointAt.setPointState(Constants.POINT_STATE_SELECTED);
// 判断是否中间点需要选中
GesturePoint betweenPoint = getBetweenCheckPoint(currentPoint, pointAt);
if (betweenPoint != null && Constants.POINT_STATE_SELECTED != betweenPoint.getPointState())
// 存在中间点并且没有被选中
Pair<GesturePoint, GesturePoint> pair1 = new Pair<GesturePoint, GesturePoint>(currentPoint, betweenPoint);
lineList.add(pair1);
passWordSb.append(betweenPoint.getNum());
Pair<GesturePoint, GesturePoint> pair2 = new Pair<GesturePoint, GesturePoint>(betweenPoint, pointAt);
lineList.add(pair2);
passWordSb.append(pointAt.getNum());
// 设置中间点选中
betweenPoint.setPointState(Constants.POINT_STATE_SELECTED);
// 赋值当前的point;
currentPoint = pointAt;
else
Pair<GesturePoint, GesturePoint> pair = new Pair<GesturePoint, GesturePoint>(currentPoint, pointAt);
lineList.add(pair);
passWordSb.append(pointAt.getNum());
// 赋值当前的point;
currentPoint = pointAt;
invalidate();
break;
case MotionEvent.ACTION_UP:// 当手指抬起的时候
if (isVerify)
// 手势密码校验
// 清掉屏幕上所有的线,只画上集合里面保存的线
if (passWord.equals(passWordSb.toString()))
// 代表用户绘制的密码手势与传入的密码相同
callBack.checkedSuccess();
else
// 用户绘制的密码与传入的密码不同。
callBack.checkedFail();
else
callBack.onGestureCodeInput(passWordSb.toString());
break;
default:
break;
return true;
/**
* 指定时间去清除绘制的状态
* @param delayTime 延迟执行时间
*/
public void clearDrawlineState(long delayTime)
if (delayTime > 0)
// 绘制红色提示路线
isDrawEnable = false;
drawErrorPathTip();
new Handler().postDelayed(new clearStateRunnable(), delayTime);
/**
* 清除绘制状态的线程
*/
final class clearStateRunnable implements Runnable
public void run()
// 重置passWordSb
passWordSb = new StringBuilder();
// 清空保存点的集合
lineList.clear();
// 重新绘制界面
clearScreenAndDrawList();
for (GesturePoint p : list)
p.setPointState(Constants.POINT_STATE_NORMAL);
invalidate();
isDrawEnable = true;
/**
* 通过点的位置去集合里面查找这个点是包含在哪个Point里面的
*
* @param x
* @param y
* @return 如果没有找到,则返回null,代表用户当前移动的地方属于点与点之间
*/
private GesturePoint getPointAt(int x, int y)
for (GesturePoint point : list)
// 先判断x
int leftX = point.getLeftX();
int rightX = point.getRightX();
if (!(x >= leftX && x < rightX))
// 如果为假,则跳到下一个对比
continue;
int topY = point.getTopY();
int bottomY = point.getBottomY();
if (!(y >= topY && y < bottomY))
// 如果为假,则跳到下一个对比
continue;
// 如果执行到这,那么说明当前点击的点的位置在遍历到点的位置这个地方
return point;
return null;
private GesturePoint getBetweenCheckPoint(GesturePoint pointStart, GesturePoint pointEnd)
int startNum = pointStart.getNum();
int endNum = pointEnd.getNum();
String key = null;
if (startNum < endNum)
key = startNum + "," + endNum;
else
key = endNum + "," + startNum;
return autoCheckPointMap.get(key);
/**
* 清掉屏幕上所有的线,然后画出集合里面的线
*/
private void clearScreenAndDrawList()
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (Pair<GesturePoint, GesturePoint> pair : lineList)
canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
/**
* 校验错误/两次绘制不一致提示
*/
private void drawErrorPathTip()
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
paint.setColor(Color.rgb(154, 7, 21));// 设置默认线路颜色
for (Pair<GesturePoint, GesturePoint> pair : lineList)
pair.first.setPointState(Constants.POINT_STATE_WRONG);
pair.second.setPointState(Constants.POINT_STATE_WRONG);
canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
invalidate();
public interface GestureCallBack
/**
* 用户设置/输入了手势密码
*/
public abstract void onGestureCodeInput(String inputCode);
/**
* 代表用户绘制的密码与传入的密码相同
*/
public abstract void checkedSuccess();
/**
* 代表用户绘制的密码与传入的密码不相同
*/
public abstract void checkedFail();
4.GestureEditActivity.java 手势密码设置界面
手势密码设置
代码如下:
package com.wujay.fund;
import com.wujay.fund.R;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.html;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.wujay.fund.common.Constants;
import com.wujay.fund.widget.GestureContentView;
import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
import com.wujay.fund.widget.LockIndicator;
/**
*
* 手势密码设置界面
*
*/
public class GestureEditActivity extends Activity implements OnClickListener
/** 手机号码*/
public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
/** 意图 */
public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
/** 首次提示绘制手势密码,可以选择跳过 */
public static final String PARAM_IS_FIRST_ADVICE = "PARAM_IS_FIRST_ADVICE";
private TextView mTextTitle;
private TextView mTextCancel;
private LockIndicator mLockIndicator;
private TextView mTextTip;
private FrameLayout mGestureContainer;
private GestureContentView mGestureContentView;
private TextView mTextReset;
private String mParamSetUpcode = null;
private String mParamPhoneNumber;
private boolean mIsFirstInput = true;
private String mFirstPassword = null;
private String mConfirmPassword = null;
private int mParamIntentCode;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gesture_edit);
setUpViews();
setUpListeners();
private void setUpViews()
mTextTitle = (TextView) findViewById(R.id.text_title);
mTextCancel = (TextView) findViewById(R.id.text_cancel);
mTextReset = (TextView) findViewById(R.id.text_reset);
mTextReset.setClickable(false);
mLockIndicator = (LockIndicator) findViewById(R.id.lock_indicator);
mTextTip = (TextView) findViewById(R.id.text_tip);
mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
// 初始化一个显示各个点的viewGroup
mGestureContentView = new GestureContentView(this, false, "", new GestureCallBack()
@Override
public void onGestureCodeInput(String inputCode)
if (!isInputPassValidate(inputCode))
mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>最少链接4个点, 请重新输入</font>"));
mGestureContentView.clearDrawlineState(0L);
return;
if (mIsFirstInput)
mFirstPassword = inputCode;
updateCodeList(inputCode);
mGestureContentView.clearDrawlineState(0L);
mTextReset.setClickable(true);
mTextReset.setText(getString(R.string.reset_gesture_code));
else
if (inputCode.equals(mFirstPassword))
Toast.makeText(GestureEditActivity.this, "设置成功", Toast.LENGTH_SHORT).show();
mGestureContentView.clearDrawlineState(0L);
GestureEditActivity.this.finish();
else
mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>与上一次绘制不一致,请重新绘制</font>"));
// 左右移动动画
Animation shakeAnimation = AnimationUtils.loadAnimation(GestureEditActivity.this, R.anim.shake);
mTextTip.startAnimation(shakeAnimation);
// 保持绘制的线,1.5秒后清除
mGestureContentView.clearDrawlineState(1300L);
mIsFirstInput = false;
@Override
public void checkedSuccess()
@Override
public void checkedFail()
);
// 设置手势解锁显示到哪个布局里面
mGestureContentView.setParentView(mGestureContainer);
updateCodeList("");
private void setUpListeners()
mTextCancel.setOnClickListener(this);
mTextReset.setOnClickListener(this);
private void updateCodeList(String inputCode)
// 更新选择的图案
mLockIndicator.setPath(inputCode);
@Override
public void onClick(View v)
switch (v.getId())
case R.id.text_cancel:
this.finish();
break;
case R.id.text_reset:
mIsFirstInput = true;
updateCodeList("");
mTextTip.setText(getString(R.string.set_gesture_pattern));
break;
default:
break;
private boolean isInputPassValidate(String inputPassword)
if (TextUtils.isEmpty(inputPassword) || inputPassword.length() < 4)
return false;
return true;
5. GestureVerifyActivity.java 手势密码校验界面
代码如下:
package com.wujay.fund;
import com.wujay.fund.R;
import com.wujay.fund.widget.GestureContentView;
import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
*
* 手势绘制/校验界面
*
*/
public class GestureVerifyActivity extends Activity implements android.view.View.OnClickListener
/** 手机号码*/
public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
/** 意图 */
public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
private RelativeLayout mTopLayout;
private TextView mTextTitle;
private TextView mTextCancel;
private ImageView mImgUserLogo;
private TextView mTextPhoneNumber;
private TextView mTextTip;
private FrameLayout mGestureContainer;
private GestureContentView mGestureContentView;
private TextView mTextForget;
private TextView mTextOther;
private String mParamPhoneNumber;
private long mExitTime = 0;
private int mParamIntentCode;
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gesture_verify);
ObtainExtraData();
setUpViews();
setUpListeners();
private void ObtainExtraData()
mParamPhoneNumber = getIntent().getStringExtra(PARAM_PHONE_NUMBER);
mParamIntentCode = getIntent().getIntExtra(PARAM_INTENT_CODE, 0);
private void setUpViews()
mTopLayout = (RelativeLayout) findViewById(R.id.top_layout);
mTextTitle = (TextView) findViewById(R.id.text_title);
mTextCancel = (TextView) findViewById(R.id.text_cancel);
mImgUserLogo = (ImageView) findViewById(R.id.user_logo);
mTextPhoneNumber = (TextView) findViewById(R.id.text_phone_number);
mTextTip = (TextView) findViewById(R.id.text_tip);
mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
mTextForget = (TextView) findViewById(R.id.text_forget_gesture);
mTextOther = (TextView) findViewById(R.id.text_other_account);
// 初始化一个显示各个点的viewGroup
mGestureContentView = new GestureContentView(this, true, "1235789",
new GestureCallBack()
@Override
public void onGestureCodeInput(String inputCode)
@Override
public void checkedSuccess()
mGestureContentView.clearDrawlineState(0L);
Toast.makeText(GestureVerifyActivity.this, "密码正确", 1000).show();
GestureVerifyActivity.this.finish();
@Override
public void checkedFail()
mGestureContentView.clearDrawlineState(1300L);
mTextTip.setVisibility(View.VISIBLE);
mTextTip.setText(Html
.fromHtml("<font color='#c70c1e'>密码错误</font>"));
// 左右移动动画
Animation shakeAnimation = AnimationUtils.loadAnimation(GestureVerifyActivity.this, R.anim.shake);
mTextTip.startAnimation(shakeAnimation);
);
// 设置手势解锁显示到哪个布局里面
mGestureContentView.setParentView(mGestureContainer);
private void setUpListeners()
mTextCancel.setOnClickListener(this);
mTextForget.setOnClickListener(this);
mTextOther.setOnClickListener(this);
private String getProtectedMobile(String phoneNumber)
if (TextUtils.isEmpty(phoneNumber) || phoneNumber.length() < 11)
return "";
StringBuilder builder = new StringBuilder();
builder.append(phoneNumber.subSequence(0,3));
builder.append("****");
builder.append(phoneNumber.subSequence(7,11));
return builder.toString();
@Override
public void onClick(View v)
switch (v.getId())
case R.id.text_cancel:
this.finish();
break;
default:
break;
以上是手势密码实现的关键代码,我把项目中的模块代码整理出来,新建了一个project,供大家分享和交流
源码下载地址:
git代码地址(试用Studio):https://github.com/wulianghuan/Gesture_Lock_Master
源码下载地址(试用Eclipse):http://download.csdn.net/detail/wulianghuan/8115995
以上是关于招财进宝手势锁,Android手势密码的实现的主要内容,如果未能解决你的问题,请参考以下文章