这篇来分享一下绘制手势密码的实现(主要是设置手势密码、校验手势密码):

一、大致界面介绍:

                    

图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 图案提示类

[java] view plaincopy print?
  1. package com.snda.fund.widget;
  2. import com.snda.fund.R;
  3. import android.content.Context;
  4. import android.content.res.TypedArray;
  5. import android.graphics.Canvas;
  6. import android.graphics.Paint;
  7. import android.graphics.Paint.Style;
  8. import android.graphics.drawable.Drawable;
  9. import android.os.PowerManager;
  10. import android.text.TextUtils;
  11. import android.util.AttributeSet;
  12. import android.util.Log;
  13. import android.view.View;
  14. /**
  15. *
  16. * 手势密码图案提示
  17. * @author wulianghuan
  18. *
  19. */
  20. public class LockIndicator extends View {
  21. private int numRow = 3; // 行
  22. private int numColum = 3; // 列
  23. private int patternWidth = 40;
  24. private int patternHeight = 40;
  25. private int f = 5;
  26. private int g = 5;
  27. private int strokeWidth = 3;
  28. private Paint paint = null;
  29. private Drawable patternNoraml = null;
  30. private Drawable patternPressed = null;
  31. private String lockPassStr; // 手势密码
  32. public LockIndicator(Context paramContext) {
  33. super(paramContext);
  34. }
  35. public LockIndicator(Context paramContext, AttributeSet paramAttributeSet) {
  36. super(paramContext, paramAttributeSet, 0);
  37. paint = new Paint();
  38. paint.setAntiAlias(true);
  39. paint.setStrokeWidth(strokeWidth);
  40. paint.setStyle(Paint.Style.STROKE);
  41. patternNoraml = getResources().getDrawable(R.drawable.lock_pattern_node_normal);
  42. patternPressed = getResources().getDrawable(R.drawable.lock_pattern_node_pressed);
  43. if (patternPressed != null) {
  44. patternWidth = patternPressed.getIntrinsicWidth();
  45. patternHeight = patternPressed.getIntrinsicHeight();
  46. this.f = (patternWidth / 4);
  47. this.g = (patternHeight / 4);
  48. patternPressed.setBounds(0, 0, patternWidth, patternHeight);
  49. patternNoraml.setBounds(0, 0, patternWidth, patternHeight);
  50. }
  51. }
  52. @Override
  53. protected void onDraw(Canvas canvas) {
  54. if ((patternPressed == null) || (patternNoraml == null)) {
  55. return;
  56. }
  57. // 绘制3*3的图标
  58. for (int i = 0; i < numRow; i++) {
  59. for (int j = 0; j < numColum; j++) {
  60. paint.setColor(-16777216);
  61. int i1 = j * patternHeight + j * this.g;
  62. int i2 = i * patternWidth + i * this.f;
  63. canvas.save();
  64. canvas.translate(i1, i2);
  65. String curNum = String.valueOf(numColum * i + (j + 1));
  66. if (!TextUtils.isEmpty(lockPassStr)) {
  67. if (lockPassStr.indexOf(curNum) == -1) {
  68. // 未选中
  69. patternNoraml.draw(canvas);
  70. } else {
  71. // 被选中
  72. patternPressed.draw(canvas);
  73. }
  74. } else {
  75. // 重置状态
  76. patternNoraml.draw(canvas);
  77. }
  78. canvas.restore();
  79. }
  80. }
  81. }
  82. @Override
  83. protected void onMeasure(int paramInt1, int paramInt2) {
  84. if (patternPressed != null)
  85. setMeasuredDimension(numColum * patternHeight + this.g
  86. * (-1 + numColum), numRow * patternWidth + this.f
  87. * (-1 + numRow));
  88. }
  89. /**
  90. * 请求重新绘制
  91. * @param paramString 手势密码字符序列
  92. */
  93. public void setPath(String paramString) {
  94. lockPassStr = paramString;
  95. invalidate();
  96. }
  97. }

2. GestureContentView.java  手势密码容器类

它继承ViewGroup,通过addView()方法添加子viewe,手势密码的9个输入点(GesturePoint)、GestureDrawline手势密码路径都放在这个容器当中,下面是它的具体实现方法:

[java] view plaincopy print?
  1. package com.wujay.fund.widget;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.content.Context;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.ImageView;
  8. import com.wujay.fund.R;
  9. import com.wujay.fund.common.AppUtil;
  10. import com.wujay.fund.entity.GesturePoint;
  11. import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
  12. /**
  13. * 手势密码容器类
  14. *
  15. */
  16. public class GestureContentView extends ViewGroup {
  17. private int baseNum = 6;
  18. private int[] screenDispaly;
  19. /**
  20. * 每个点区域的宽度
  21. */
  22. private int blockWidth;
  23. /**
  24. * 声明一个集合用来封装坐标集合
  25. */
  26. private List<GesturePoint> list;
  27. private Context context;
  28. private boolean isVerify;
  29. private GestureDrawline gestureDrawline;
  30. /**
  31. * 包含9个ImageView的容器,初始化
  32. * @param context
  33. * @param isVerify 是否为校验手势密码
  34. * @param passWord 用户传入密码
  35. * @param callBack 手势绘制完毕的回调
  36. */
  37. public GestureContentView(Context context, boolean isVerify, String passWord, GestureCallBack callBack) {
  38. super(context);
  39. screenDispaly = AppUtil.getScreenDispaly(context);
  40. blockWidth = screenDispaly[0]/3;
  41. this.list = new ArrayList<GesturePoint>();
  42. this.context = context;
  43. this.isVerify = isVerify;
  44. // 添加9个图标
  45. addChild();
  46. // 初始化一个可以画线的view
  47. gestureDrawline = new GestureDrawline(context, list, isVerify, passWord, callBack);
  48. }
  49. private void addChild(){
  50. for (int i = 0; i < 9; i++) {
  51. ImageView image = new ImageView(context);
  52. image.setBackgroundResource(R.drawable.gesture_node_normal);
  53. this.addView(image);
  54. invalidate();
  55. // 第几行
  56. int row = i / 3;
  57. // 第几列
  58. int col = i % 3;
  59. // 定义点的每个属性
  60. int leftX = col*blockWidth+blockWidth/baseNum;
  61. int topY = row*blockWidth+blockWidth/baseNum;
  62. int rightX = col*blockWidth+blockWidth-blockWidth/baseNum;
  63. int bottomY = row*blockWidth+blockWidth-blockWidth/baseNum;
  64. GesturePoint p = new GesturePoint(leftX, rightX, topY, bottomY, image,i+1);
  65. this.list.add(p);
  66. }
  67. }
  68. public void setParentView(ViewGroup parent){
  69. // 得到屏幕的宽度
  70. int width = screenDispaly[0];
  71. LayoutParams layoutParams = new LayoutParams(width, width);
  72. this.setLayoutParams(layoutParams);
  73. gestureDrawline.setLayoutParams(layoutParams);
  74. parent.addView(gestureDrawline);
  75. parent.addView(this);
  76. }
  77. @Override
  78. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  79. for (int i = 0; i < getChildCount(); i++) {
  80. //第几行
  81. int row = i/3;
  82. //第几列
  83. int col = i%3;
  84. View v = getChildAt(i);
  85. v.layout(col*blockWidth+blockWidth/baseNum, row*blockWidth+blockWidth/baseNum,
  86. col*blockWidth+blockWidth-blockWidth/baseNum, row*blockWidth+blockWidth-blockWidth/baseNum);
  87. }
  88. }
  89. @Override
  90. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  91. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  92. // 遍历设置每个子view的大小
  93. for (int i = 0; i < getChildCount(); i++) {
  94. View v = getChildAt(i);
  95. v.measure(widthMeasureSpec, heightMeasureSpec);
  96. }
  97. }
  98. /**
  99. * 保留路径delayTime时间长
  100. * @param delayTime
  101. */
  102. public void clearDrawlineState(long delayTime) {
  103. gestureDrawline.clearDrawlineState(delayTime);
  104. }
  105. }

3. GestureDrawline.java 手势密码路径绘制类

根据OnTouchEvent方法的不同事件,ACTION_DOWN、ACTION_MOVE、ACTION_UP分别处理不同的逻辑。

[java] view plaincopy print?
  1. package com.wujay.fund.widget;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. import com.wujay.fund.common.AppUtil;
  7. import com.wujay.fund.common.Constants;
  8. import com.wujay.fund.entity.GesturePoint;
  9. import android.content.Context;
  10. import android.graphics.Bitmap;
  11. import android.graphics.Canvas;
  12. import android.graphics.Color;
  13. import android.graphics.Paint;
  14. import android.graphics.Paint.Style;
  15. import android.graphics.PorterDuff;
  16. import android.os.Handler;
  17. import android.util.Log;
  18. import android.util.Pair;
  19. import android.view.MotionEvent;
  20. import android.view.View;
  21. import android.widget.Toast;
  22. /**
  23. * 手势密码路径绘制
  24. *
  25. */
  26. public class GestureDrawline extends View {
  27. private int mov_x;// 声明起点坐标
  28. private int mov_y;
  29. private Paint paint;// 声明画笔
  30. private Canvas canvas;// 画布
  31. private Bitmap bitmap;// 位图
  32. private List<GesturePoint> list;// 装有各个view坐标的集合
  33. private List<Pair<GesturePoint, GesturePoint>> lineList;// 记录画过的线
  34. private Map<String, GesturePoint> autoCheckPointMap;// 自动选中的情况点
  35. private boolean isDrawEnable = true; // 是否允许绘制
  36. /**
  37. * 屏幕的宽度和高度
  38. */
  39. private int[] screenDispaly;
  40. /**
  41. * 手指当前在哪个Point内
  42. */
  43. private GesturePoint currentPoint;
  44. /**
  45. * 用户绘图的回调
  46. */
  47. private GestureCallBack callBack;
  48. /**
  49. * 用户当前绘制的图形密码
  50. */
  51. private StringBuilder passWordSb;
  52. /**
  53. * 是否为校验
  54. */
  55. private boolean isVerify;
  56. /**
  57. * 用户传入的passWord
  58. */
  59. private String passWord;
  60. public GestureDrawline(Context context, List<GesturePoint> list, boolean isVerify,
  61. String passWord, GestureCallBack callBack) {
  62. super(context);
  63. screenDispaly = AppUtil.getScreenDispaly(context);
  64. paint = new Paint(Paint.DITHER_FLAG);// 创建一个画笔
  65. bitmap = Bitmap.createBitmap(screenDispaly[0], screenDispaly[0], Bitmap.Config.ARGB_8888); // 设置位图的宽高
  66. canvas = new Canvas();
  67. canvas.setBitmap(bitmap);
  68. paint.setStyle(Style.STROKE);// 设置非填充
  69. paint.setStrokeWidth(10);// 笔宽5像素
  70. paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
  71. paint.setAntiAlias(true);// 不显示锯齿
  72. this.list = list;
  73. this.lineList = new ArrayList<Pair<GesturePoint, GesturePoint>>();
  74. initAutoCheckPointMap();
  75. this.callBack = callBack;
  76. // 初始化密码缓存
  77. this.isVerify = isVerify;
  78. this.passWordSb = new StringBuilder();
  79. this.passWord = passWord;
  80. }
  81. private void initAutoCheckPointMap() {
  82. autoCheckPointMap = new HashMap<String,GesturePoint>();
  83. autoCheckPointMap.put("1,3", getGesturePointByNum(2));
  84. autoCheckPointMap.put("1,7", getGesturePointByNum(4));
  85. autoCheckPointMap.put("1,9", getGesturePointByNum(5));
  86. autoCheckPointMap.put("2,8", getGesturePointByNum(5));
  87. autoCheckPointMap.put("3,7", getGesturePointByNum(5));
  88. autoCheckPointMap.put("3,9", getGesturePointByNum(6));
  89. autoCheckPointMap.put("4,6", getGesturePointByNum(5));
  90. autoCheckPointMap.put("7,9", getGesturePointByNum(8));
  91. }
  92. private GesturePoint getGesturePointByNum(int num) {
  93. for (GesturePoint point : list) {
  94. if (point.getNum() == num) {
  95. return point;
  96. }
  97. }
  98. return null;
  99. }
  100. // 画位图
  101. @Override
  102. protected void onDraw(Canvas canvas) {
  103. // super.onDraw(canvas);
  104. canvas.drawBitmap(bitmap, 0, 0, null);
  105. }
  106. // 触摸事件
  107. @Override
  108. public boolean onTouchEvent(MotionEvent event) {
  109. if (isDrawEnable == false) {
  110. // 当期不允许绘制
  111. return true;
  112. }
  113. paint.setColor(Color.rgb(245, 142, 33));// 设置默认连线颜色
  114. switch (event.getAction()) {
  115. case MotionEvent.ACTION_DOWN:
  116. mov_x = (int) event.getX();
  117. mov_y = (int) event.getY();
  118. // 判断当前点击的位置是处于哪个点之内
  119. currentPoint = getPointAt(mov_x, mov_y);
  120. if (currentPoint != null) {
  121. currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
  122. passWordSb.append(currentPoint.getNum());
  123. }
  124. // canvas.drawPoint(mov_x, mov_y, paint);// 画点
  125. invalidate();
  126. break;
  127. case MotionEvent.ACTION_MOVE:
  128. clearScreenAndDrawList();
  129. // 得到当前移动位置是处于哪个点内
  130. GesturePoint pointAt = getPointAt((int) event.getX(), (int) event.getY());
  131. // 代表当前用户手指处于点与点之前
  132. if (currentPoint == null && pointAt == null) {
  133. return true;
  134. } else {// 代表用户的手指移动到了点上
  135. if (currentPoint == null) {// 先判断当前的point是不是为null
  136. // 如果为空,那么把手指移动到的点赋值给currentPoint
  137. currentPoint = pointAt;
  138. // 把currentPoint这个点设置选中为true;
  139. currentPoint.setPointState(Constants.POINT_STATE_SELECTED);
  140. passWordSb.append(currentPoint.getNum());
  141. }
  142. }
  143. if (pointAt == null || currentPoint.equals(pointAt) || Constants.POINT_STATE_SELECTED == pointAt.getPointState()) {
  144. // 点击移动区域不在圆的区域,或者当前点击的点与当前移动到的点的位置相同,或者当前点击的点处于选中状态
  145. // 那么以当前的点中心为起点,以手指移动位置为终点画线
  146. canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), event.getX(), event.getY(), paint);// 画线
  147. } else {
  148. // 如果当前点击的点与当前移动到的点的位置不同
  149. // 那么以前前点的中心为起点,以手移动到的点的位置画线
  150. canvas.drawLine(currentPoint.getCenterX(), currentPoint.getCenterY(), pointAt.getCenterX(), pointAt.getCenterY(), paint);// 画线
  151. pointAt.setPointState(Constants.POINT_STATE_SELECTED);
  152. // 判断是否中间点需要选中
  153. GesturePoint betweenPoint = getBetweenCheckPoint(currentPoint, pointAt);
  154. if (betweenPoint != null && Constants.POINT_STATE_SELECTED != betweenPoint.getPointState()) {
  155. // 存在中间点并且没有被选中
  156. Pair<GesturePoint, GesturePoint> pair1 = new Pair<GesturePoint, GesturePoint>(currentPoint, betweenPoint);
  157. lineList.add(pair1);
  158. passWordSb.append(betweenPoint.getNum());
  159. Pair<GesturePoint, GesturePoint> pair2 = new Pair<GesturePoint, GesturePoint>(betweenPoint, pointAt);
  160. lineList.add(pair2);
  161. passWordSb.append(pointAt.getNum());
  162. // 设置中间点选中
  163. betweenPoint.setPointState(Constants.POINT_STATE_SELECTED);
  164. // 赋值当前的point;
  165. currentPoint = pointAt;
  166. } else {
  167. Pair<GesturePoint, GesturePoint> pair = new Pair<GesturePoint, GesturePoint>(currentPoint, pointAt);
  168. lineList.add(pair);
  169. passWordSb.append(pointAt.getNum());
  170. // 赋值当前的point;
  171. currentPoint = pointAt;
  172. }
  173. }
  174. invalidate();
  175. break;
  176. case MotionEvent.ACTION_UP:// 当手指抬起的时候
  177. if (isVerify) {
  178. // 手势密码校验
  179. // 清掉屏幕上所有的线,只画上集合里面保存的线
  180. if (passWord.equals(passWordSb.toString())) {
  181. // 代表用户绘制的密码手势与传入的密码相同
  182. callBack.checkedSuccess();
  183. } else {
  184. // 用户绘制的密码与传入的密码不同。
  185. callBack.checkedFail();
  186. }
  187. } else {
  188. callBack.onGestureCodeInput(passWordSb.toString());
  189. }
  190. break;
  191. default:
  192. break;
  193. }
  194. return true;
  195. }
  196. /**
  197. * 指定时间去清除绘制的状态
  198. * @param delayTime 延迟执行时间
  199. */
  200. public void clearDrawlineState(long delayTime) {
  201. if (delayTime > 0) {
  202. // 绘制红色提示路线
  203. isDrawEnable = false;
  204. drawErrorPathTip();
  205. }
  206. new Handler().postDelayed(new clearStateRunnable(), delayTime);
  207. }
  208. /**
  209. * 清除绘制状态的线程
  210. */
  211. final class clearStateRunnable implements Runnable {
  212. public void run() {
  213. // 重置passWordSb
  214. passWordSb = new StringBuilder();
  215. // 清空保存点的集合
  216. lineList.clear();
  217. // 重新绘制界面
  218. clearScreenAndDrawList();
  219. for (GesturePoint p : list) {
  220. p.setPointState(Constants.POINT_STATE_NORMAL);
  221. }
  222. invalidate();
  223. isDrawEnable = true;
  224. }
  225. }
  226. /**
  227. * 通过点的位置去集合里面查找这个点是包含在哪个Point里面的
  228. *
  229. * @param x
  230. * @param y
  231. * @return 如果没有找到,则返回null,代表用户当前移动的地方属于点与点之间
  232. */
  233. private GesturePoint getPointAt(int x, int y) {
  234. for (GesturePoint point : list) {
  235. // 先判断x
  236. int leftX = point.getLeftX();
  237. int rightX = point.getRightX();
  238. if (!(x >= leftX && x < rightX)) {
  239. // 如果为假,则跳到下一个对比
  240. continue;
  241. }
  242. int topY = point.getTopY();
  243. int bottomY = point.getBottomY();
  244. if (!(y >= topY && y < bottomY)) {
  245. // 如果为假,则跳到下一个对比
  246. continue;
  247. }
  248. // 如果执行到这,那么说明当前点击的点的位置在遍历到点的位置这个地方
  249. return point;
  250. }
  251. return null;
  252. }
  253. private GesturePoint getBetweenCheckPoint(GesturePoint pointStart, GesturePoint pointEnd) {
  254. int startNum = pointStart.getNum();
  255. int endNum = pointEnd.getNum();
  256. String key = null;
  257. if (startNum < endNum) {
  258. key = startNum + "," + endNum;
  259. } else {
  260. key = endNum + "," + startNum;
  261. }
  262. return autoCheckPointMap.get(key);
  263. }
  264. /**
  265. * 清掉屏幕上所有的线,然后画出集合里面的线
  266. */
  267. private void clearScreenAndDrawList() {
  268. canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
  269. for (Pair<GesturePoint, GesturePoint> pair : lineList) {
  270. canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
  271. pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
  272. }
  273. }
  274. /**
  275. * 校验错误/两次绘制不一致提示
  276. */
  277. private void drawErrorPathTip() {
  278. canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
  279. paint.setColor(Color.rgb(154, 7, 21));// 设置默认线路颜色
  280. for (Pair<GesturePoint, GesturePoint> pair : lineList) {
  281. pair.first.setPointState(Constants.POINT_STATE_WRONG);
  282. pair.second.setPointState(Constants.POINT_STATE_WRONG);
  283. canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),
  284. pair.second.getCenterX(), pair.second.getCenterY(), paint);// 画线
  285. }
  286. invalidate();
  287. }
  288. public interface GestureCallBack {
  289. /**
  290. * 用户设置/输入了手势密码
  291. */
  292. public abstract void onGestureCodeInput(String inputCode);
  293. /**
  294. * 代表用户绘制的密码与传入的密码相同
  295. */
  296. public abstract void checkedSuccess();
  297. /**
  298. * 代表用户绘制的密码与传入的密码不相同
  299. */
  300. public abstract void checkedFail();
  301. }
  302. }

4.GestureEditActivity.java 手势密码设置界面

手势密码设置

代码如下:

[java] view plaincopy print?
  1. package com.wujay.fund;
  2. import com.wujay.fund.R;
  3. import android.app.Activity;
  4. import android.content.DialogInterface;
  5. import android.content.Intent;
  6. import android.os.Bundle;
  7. import android.text.Html;
  8. import android.text.TextUtils;
  9. import android.view.KeyEvent;
  10. import android.view.View;
  11. import android.view.View.OnClickListener;
  12. import android.view.animation.Animation;
  13. import android.view.animation.AnimationUtils;
  14. import android.widget.FrameLayout;
  15. import android.widget.TextView;
  16. import android.widget.Toast;
  17. import com.wujay.fund.common.Constants;
  18. import com.wujay.fund.widget.GestureContentView;
  19. import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
  20. import com.wujay.fund.widget.LockIndicator;
  21. /**
  22. *
  23. * 手势密码设置界面
  24. *
  25. */
  26. public class GestureEditActivity extends Activity implements OnClickListener {
  27. /** 手机号码*/
  28. public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
  29. /** 意图 */
  30. public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
  31. /** 首次提示绘制手势密码,可以选择跳过 */
  32. public static final String PARAM_IS_FIRST_ADVICE = "PARAM_IS_FIRST_ADVICE";
  33. private TextView mTextTitle;
  34. private TextView mTextCancel;
  35. private LockIndicator mLockIndicator;
  36. private TextView mTextTip;
  37. private FrameLayout mGestureContainer;
  38. private GestureContentView mGestureContentView;
  39. private TextView mTextReset;
  40. private String mParamSetUpcode = null;
  41. private String mParamPhoneNumber;
  42. private boolean mIsFirstInput = true;
  43. private String mFirstPassword = null;
  44. private String mConfirmPassword = null;
  45. private int mParamIntentCode;
  46. @Override
  47. public void onCreate(Bundle savedInstanceState) {
  48. super.onCreate(savedInstanceState);
  49. setContentView(R.layout.activity_gesture_edit);
  50. setUpViews();
  51. setUpListeners();
  52. }
  53. private void setUpViews() {
  54. mTextTitle = (TextView) findViewById(R.id.text_title);
  55. mTextCancel = (TextView) findViewById(R.id.text_cancel);
  56. mTextReset = (TextView) findViewById(R.id.text_reset);
  57. mTextReset.setClickable(false);
  58. mLockIndicator = (LockIndicator) findViewById(R.id.lock_indicator);
  59. mTextTip = (TextView) findViewById(R.id.text_tip);
  60. mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
  61. // 初始化一个显示各个点的viewGroup
  62. mGestureContentView = new GestureContentView(this, false, "", new GestureCallBack() {
  63. @Override
  64. public void onGestureCodeInput(String inputCode) {
  65. if (!isInputPassValidate(inputCode)) {
  66. mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>最少链接4个点, 请重新输入</font>"));
  67. mGestureContentView.clearDrawlineState(0L);
  68. return;
  69. }
  70. if (mIsFirstInput) {
  71. mFirstPassword = inputCode;
  72. updateCodeList(inputCode);
  73. mGestureContentView.clearDrawlineState(0L);
  74. mTextReset.setClickable(true);
  75. mTextReset.setText(getString(R.string.reset_gesture_code));
  76. } else {
  77. if (inputCode.equals(mFirstPassword)) {
  78. Toast.makeText(GestureEditActivity.this, "设置成功", Toast.LENGTH_SHORT).show();
  79. mGestureContentView.clearDrawlineState(0L);
  80. GestureEditActivity.this.finish();
  81. } else {
  82. mTextTip.setText(Html.fromHtml("<font color='#c70c1e'>与上一次绘制不一致,请重新绘制</font>"));
  83. // 左右移动动画
  84. Animation shakeAnimation = AnimationUtils.loadAnimation(GestureEditActivity.this, R.anim.shake);
  85. mTextTip.startAnimation(shakeAnimation);
  86. // 保持绘制的线,1.5秒后清除
  87. mGestureContentView.clearDrawlineState(1300L);
  88. }
  89. }
  90. mIsFirstInput = false;
  91. }
  92. @Override
  93. public void checkedSuccess() {
  94. }
  95. @Override
  96. public void checkedFail() {
  97. }
  98. });
  99. // 设置手势解锁显示到哪个布局里面
  100. mGestureContentView.setParentView(mGestureContainer);
  101. updateCodeList("");
  102. }
  103. private void setUpListeners() {
  104. mTextCancel.setOnClickListener(this);
  105. mTextReset.setOnClickListener(this);
  106. }
  107. private void updateCodeList(String inputCode) {
  108. // 更新选择的图案
  109. mLockIndicator.setPath(inputCode);
  110. }
  111. @Override
  112. public void onClick(View v) {
  113. switch (v.getId()) {
  114. case R.id.text_cancel:
  115. this.finish();
  116. break;
  117. case R.id.text_reset:
  118. mIsFirstInput = true;
  119. updateCodeList("");
  120. mTextTip.setText(getString(R.string.set_gesture_pattern));
  121. break;
  122. default:
  123. break;
  124. }
  125. }
  126. private boolean isInputPassValidate(String inputPassword) {
  127. if (TextUtils.isEmpty(inputPassword) || inputPassword.length() < 4) {
  128. return false;
  129. }
  130. return true;
  131. }
  132. }

5. GestureVerifyActivity.java 手势密码校验界面

代码如下:

[java] view plaincopy print?
  1. package com.wujay.fund;
  2. import com.wujay.fund.R;
  3. import com.wujay.fund.widget.GestureContentView;
  4. import com.wujay.fund.widget.GestureDrawline.GestureCallBack;
  5. import android.app.Activity;
  6. import android.app.Dialog;
  7. import android.content.DialogInterface;
  8. import android.content.DialogInterface.OnClickListener;
  9. import android.content.Intent;
  10. import android.os.Bundle;
  11. import android.text.Html;
  12. import android.text.TextUtils;
  13. import android.view.KeyEvent;
  14. import android.view.View;
  15. import android.view.animation.Animation;
  16. import android.view.animation.AnimationUtils;
  17. import android.widget.FrameLayout;
  18. import android.widget.ImageView;
  19. import android.widget.RelativeLayout;
  20. import android.widget.TextView;
  21. import android.widget.Toast;
  22. /**
  23. *
  24. * 手势绘制/校验界面
  25. *
  26. */
  27. public class GestureVerifyActivity extends Activity implements android.view.View.OnClickListener {
  28. /** 手机号码*/
  29. public static final String PARAM_PHONE_NUMBER = "PARAM_PHONE_NUMBER";
  30. /** 意图 */
  31. public static final String PARAM_INTENT_CODE = "PARAM_INTENT_CODE";
  32. private RelativeLayout mTopLayout;
  33. private TextView mTextTitle;
  34. private TextView mTextCancel;
  35. private ImageView mImgUserLogo;
  36. private TextView mTextPhoneNumber;
  37. private TextView mTextTip;
  38. private FrameLayout mGestureContainer;
  39. private GestureContentView mGestureContentView;
  40. private TextView mTextForget;
  41. private TextView mTextOther;
  42. private String mParamPhoneNumber;
  43. private long mExitTime = 0;
  44. private int mParamIntentCode;
  45. @Override
  46. public void onCreate(Bundle savedInstanceState) {
  47. super.onCreate(savedInstanceState);
  48. setContentView(R.layout.activity_gesture_verify);
  49. ObtainExtraData();
  50. setUpViews();
  51. setUpListeners();
  52. }
  53. private void ObtainExtraData() {
  54. mParamPhoneNumber = getIntent().getStringExtra(PARAM_PHONE_NUMBER);
  55. mParamIntentCode = getIntent().getIntExtra(PARAM_INTENT_CODE, 0);
  56. }
  57. private void setUpViews() {
  58. mTopLayout = (RelativeLayout) findViewById(R.id.top_layout);
  59. mTextTitle = (TextView) findViewById(R.id.text_title);
  60. mTextCancel = (TextView) findViewById(R.id.text_cancel);
  61. mImgUserLogo = (ImageView) findViewById(R.id.user_logo);
  62. mTextPhoneNumber = (TextView) findViewById(R.id.text_phone_number);
  63. mTextTip = (TextView) findViewById(R.id.text_tip);
  64. mGestureContainer = (FrameLayout) findViewById(R.id.gesture_container);
  65. mTextForget = (TextView) findViewById(R.id.text_forget_gesture);
  66. mTextOther = (TextView) findViewById(R.id.text_other_account);
  67. // 初始化一个显示各个点的viewGroup
  68. mGestureContentView = new GestureContentView(this, true, "1235789",
  69. new GestureCallBack() {
  70. @Override
  71. public void onGestureCodeInput(String inputCode) {
  72. }
  73. @Override
  74. public void checkedSuccess() {
  75. mGestureContentView.clearDrawlineState(0L);
  76. Toast.makeText(GestureVerifyActivity.this, "密码正确", 1000).show();
  77. GestureVerifyActivity.this.finish();
  78. }
  79. @Override
  80. public void checkedFail() {
  81. mGestureContentView.clearDrawlineState(1300L);
  82. mTextTip.setVisibility(View.VISIBLE);
  83. mTextTip.setText(Html
  84. .fromHtml("<font color='#c70c1e'>密码错误</font>"));
  85. // 左右移动动画
  86. Animation shakeAnimation = AnimationUtils.loadAnimation(GestureVerifyActivity.this, R.anim.shake);
  87. mTextTip.startAnimation(shakeAnimation);
  88. }
  89. });
  90. // 设置手势解锁显示到哪个布局里面
  91. mGestureContentView.setParentView(mGestureContainer);
  92. }
  93. private void setUpListeners() {
  94. mTextCancel.setOnClickListener(this);
  95. mTextForget.setOnClickListener(this);
  96. mTextOther.setOnClickListener(this);
  97. }
  98. private String getProtectedMobile(String phoneNumber) {
  99. if (TextUtils.isEmpty(phoneNumber) || phoneNumber.length() < 11) {
  100. return "";
  101. }
  102. StringBuilder builder = new StringBuilder();
  103. builder.append(phoneNumber.subSequence(0,3));
  104. builder.append("****");
  105. builder.append(phoneNumber.subSequence(7,11));
  106. return builder.toString();
  107. }
  108. @Override
  109. public void onClick(View v) {
  110. switch (v.getId()) {
  111. case R.id.text_cancel:
  112. this.finish();
  113. break;
  114. default:
  115. break;
  116. }
  117. }
  118. }

以上是手势密码实现的关键代码,我把项目中的模块代码整理出来,新建了一个project,供大家分享和交流

源码下载地址:

源码下载地址:http://download.csdn.net/detail/wulianghuan/8115995

Android手势密码解锁相关推荐

  1. android手势密码源码,Android自定义UI手势密码改进版源码下载

    在之前文章的铺垫下,再为大家分享一篇:Android手势密码,附源码下载,不要错过. 先看第一张图片的布局文件 activity_main.xml xmlns:tools="http://s ...

  2. 自定义View----Android九宫格手势密码解锁

    好久没更新blog了,最近公司比较忙,旧的项目上线时间赶.加上新的项目又来了,于是导致都好久没去鸿洋的群里扯蛋了,做了一个不称职的管理员.说了好多遍的自定义萌系进度条都没有分享出来,在这给群里的各位说 ...

  3. 手把手教你写一个手势密码解锁View(GesturePasswordView)

    相信大家在很多的app肯定看到过手势密码解锁View,但是大家有没有想过怎么实现这样一个View,哈,接下来,小编手把手教大家教写一个GesturePasswordView. 先看一张效果图 要实现这 ...

  4. Android手势密码view笔记(一)

    前言:不知不觉已经在这座陌生又熟悉的城市呆了一年多了,说不出什么感觉,可是即使是自己感觉自己没什么变化,但是周围的事物却不断的在变,不知道自己选择的路未来如何,但是当下我还是会努力.努力.再努力的,加 ...

  5. android手势密码csdn,Android手势密码LockPatternView、LockPasswordUtils、LockPatternUtils等分析...

    Android手势密码LockPatternView.LockPasswordUtils.LockPatternUtils 在使用别人写的这个手势密码的时候,我们通常是有自己的需求,可能这里的代码很多 ...

  6. 值得推荐的 5 大 Android 手机密码解锁器

    大多数 Android 用户使用唯一密码来保护他们的手机和重要数据.因此,忘记密码并被锁定在手机之外可能会令人沮丧.在这种情况下,使用安卓手机密码解锁器来解决问题是一个明智的选择.本文将介绍2023 ...

  7. android 手势密码功能sdk,利用ActivityLifecycleCallBack监控app前后台状态切换,实现手势密码即九宫格解锁...

    转载注明出处:http://blog..net/coderder/article/details/51063493 利用ActivityLifecycleCallbacks监控app前后台状态切换,实 ...

  8. Android手势密码探索

    Android 智能手机在全球市场有着极高的市场占有率,越来越受到广大消费者的青睐.但 Android 作为开源操作系统,且很容易可以获得系统 root 权限,Android 系统的安全问题也是用户和 ...

  9. android 手势密码逻辑,[Android开发实战]Android手势密码(支付宝手势密码)实现(支持2.x)...

    原创文章,转载请注明出处:http://blog.csdn.net/ruils/article/details/17081207 在很多安全性比较高的应用程序中,每次打开程序,都会有让用户输入密码,这 ...

  10. 招财进宝手势锁,Android手势密码的实现

    这几个月都是在做招财进宝项目,招财进宝是盛大网络旗下,盛付通支付服务有限公司最新推出的,一款高收益低风险的理财APP,有兴趣的可以下载玩玩,收益不错哦!!! 招财进宝下载地址:http://8.she ...

最新文章

  1. 利用Python基础代码语句,实现2G时代文字小游戏,世界如此简单
  2. python入门(七)
  3. Asp.Net Core 第02局:Program
  4. 【网址收藏】华为荣耀V9(DUK-AL20)刷机包下载
  5. matlab如何excel数据,Matlab如何读取Excel里的数据
  6. 带有Prometheus的弹簧靴和千分尺第5部分:旋转Prometheus
  7. 深度学习--Keras总结
  8. Android Animation时间插入器Interpolator
  9. html5自动显示日期脚本,HTML显示日期时间代码 - [js 特效代码]
  10. 硬盘分区MBR与GPT
  11. Jenkins插件Gerrit Trigger配置,实现change-merged时自动触发Jenkins工程build
  12. 也谈谈印度人的职场话题
  13. 【Web】HTML中选择器的基本用法
  14. python图标变成了白色_桌面图标上有个白色文件图标怎么去掉?解决桌面图标白色方块挡住...
  15. No suitable resolver
  16. 地磅无人值守称重系统怎样实现自动发货的?
  17. 解决微信扫码下载的两个方法
  18. 萤光云香港三区服务器测评
  19. 设计图标(logo)
  20. Live2D桌面动画模型,在桌面显示

热门文章

  1. 中国气候分布矢量图_如何用30行代码构建气候图
  2. 4.15 期货每日早盘操作建议
  3. excel制作复合饼状图_如何在Excel中制作饼图
  4. RESTful 接口设计规范
  5. 你为什么成为一名程序员?
  6. 阿里巴巴的微服务开源之路
  7. 一键添加QQ群的方式(更新中。。。)
  8. 人工智能的现状分析和未来展望
  9. Apache ab测试结果解析
  10. 二进制转十进制c++语言数组,C++实现读入二进制数并转换为十进制输出