Android应用 手势密码的实现(二)
来源:互联网 发布:android数独游戏源码 编辑:程序博客网 时间:2024/06/05 18:19
本文基于Hongyang大神的博客:http://blog.csdn.net/lmj623565791/article/details/36236113
转载请注明来源:http://blog.csdn.net/u013258802/article/details/53063691
上一篇界面修改的文章:http://blog.csdn.net/u013258802/article/details/52959513
本文的目的如下:
1、隐藏手势轨迹
2、自动重置
一、隐藏手势轨迹
1、先看 GestureLockView:
隐藏手势轨迹需要 GestureLockView 一直保持 STATUS_NO_FINGER 的绘制状态,除非用户输入错误。所以我们就需要获取手势正误的状态以及知道是否绘制路径:
// 用于设置是否绘制轨迹(箭头和内圆)private boolean showPath = true;// 默认显示// 用于标记答案是否正确private boolean isAnswerRight;public void setIsAnswerRight(boolean isRight) { isAnswerRight = isRight;}
OnDraw内 switch 块内的逻辑需要改变。
当 showPath 为 false 时,我们希望 FINGER_ON 的绘制代码绘制出 NO_FINGER 的样式,把 绘制代码和break 包在 if (showPath) {} 中即可实现这个效果。
当 showPath 为 false 并且 isAnswerRight 为 true 时,我们也希望 FINGER_UP 的绘制代码绘制出 NO_FINGER 的样式,那么同上。
根据上面的设计,我们必须保证标识最多的状态放在最上面执行,否则部分标识更新慢的话就会导致乱序,语言说明不便理解,我们下一步要更换原代码里 FINGER_UP 和 FINGER_ON 的执行顺序,想加深理解的可以暂时保持原先的顺序看看效果。
流程图:
代码:
@Overrideprotected void onDraw(Canvas canvas){ switch (mCurrentStatus) { case STATUS_FINGER_UP: // 在手指抬起后,答案错误一定会进行绘制,如果答案正确那么再判断是否显示路径 if (!isAnswerRight || showPath) { // 绘制外圆 mPaint.setColor(mColorFingerUp); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mStrokeWidth); canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint); // 绘制内圆 mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(mCenterX, mCenterY, mRadius * mInnerCircleRadiusRate, mPaint); // 绘制箭头 drawArrow(canvas); break; } case STATUS_FINGER_ON: // 在画手势密码时判断是否显示路径 if (showPath) { // 绘制外圆 mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mColorFingerOn); mPaint.setStrokeWidth(mStrokeWidth); canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint); // 绘制内圆 mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(mCenterX, mCenterY, mRadius * mInnerCircleRadiusRate, mPaint); break; } case STATUS_NO_FINGER: // 绘制外圆 mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mColorNoFingerOutter); mPaint.setStrokeWidth(mStrokeWidth / 2); canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint); // 绘制内圆 mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(mColorNoFingerInner); canvas.drawCircle(mCenterX, mCenterY, mRadius * mInnerCircleRadiusRate, mPaint); break; }}
我们需要在View的每次 onDraw 前更新 showPath 的状态,否则设置无法及时生效,因此现在要改 setMode 方法,增加一个 showPath 参数:
public void setMode(Mode mode, boolean showPath) { this.mCurrentStatus = mode; this.showPath = showPath; invalidate();}
2、接下来就是GestureLockViewGroup:
首先添加变量和set方法:
// 记录答案是否正确private boolean isAnswerRight = true;// 默认显示轨迹private boolean showPath = true;// 对外公开的set方法public void setShowPath(boolean showPath) { this.showPath = showPath;}
然后调用setMode的地方就要增加参数了,这个就不多说了,例:
mGestureLockViews[i].setMode(GestureLockView.Mode.STATUS_NO_FINGER, showPath);
在手指抬起的事件中我们需要获取答案是否正确,然后在dispacthDraw()方法中依据标识状态避开路径的绘制。
ACTION_UP事件部分(获取 isAnswerRight 的状态):
// 回调是否成功if (mOnGestureLockViewListener != null && mChoose.size() > 0) { isAnswerRight = checkAnswer();// 获取状态 setViewColor(isAnswerRight); mOnGestureLockViewListener.onGestureEvent(isAnswerRight); if (this.mTryTimes == 0) { ... }
DispatchDraw方法部分(ShowPath为 false 并且答案为 true 时不进行绘制,和流程图一致):
@Overridepublic void dispatchDraw(Canvas canvas){ super.dispatchDraw(canvas); if (!showPath && isAnswerRight) { return; } //绘制GestureLockView间的连线 if (mPath != null) {...当然这里还有点小问题,就是在画手势(ACTION_MOVE)过程中,会因为上一次的错误答案导致 isAnswerRight 为 false 并进入绘制流程,所以需要在reset时把 isAnswerRight 初始化为 true:
private void reset(){ mChoose.clear(); mPath.reset(); isAnswerRight = true;// 重置 for (GestureLockView gestureLockView : mGestureLockViews) { gestureLockView.setMode(GestureLockView.Mode.STATUS_NO_FINGER, showPath); gestureLockView.setArrowDegree(-1); }}
最后我们在changeItemMode 方法中调用之前为GestureLockView 添加的 setIsAnswerRight() 方法:
private void changeItemMode(){ for (GestureLockView gestureLockView : mGestureLockViews) { if (mChoose.contains(gestureLockView.getId())) { gestureLockView.setViewColor(mFingerUpColor); gestureLockView.setIsAnswerRight(isAnswerRight);// 调用 gestureLockView.setMode(GestureLockView.Mode.STATUS_FINGER_UP, showPath); } }}
好了,现在在Activity中调用setShowPath()方法:
mGesture = (GestureLockViewGroup) findViewById(R.id.gesture_lock_view_group);mGesture.setAnswer(...);mGesture.setShowPath(false);// 调用
运行结果,只有错误时才显示路径:
二、自动重置
GestureLockViewGroup的 ACTION_DOWN 触摸事件里用到了reset(),可见落指时页面内容会重置,但我希望画完手势过一秒左右自动清空,所以写个方法delayReset(),delayReset()会延时1000ms执行reset()。
private Handler mHandler = new Handler();private Runnable mRunnable = new Runnable() { @Override public void run() { reset(); invalidate(); }};private void delayReset() { mHandler.postDelayed(mRunnable, 1000);// 加入线程队列}
这里需要留心在延时的时候用户点击界面的情况,所以在 reset() 方法执行时,如果存在延时操作则把延时的操作取消:
private void reset(){ if (mHandler != null && mRunnable != null) { mHandler.removeCallbacks(mRunnable);// 从线程队列中移除 } mChoose.clear(); mPath.reset(); ...
然后在 ACTION_UP 里 break 之前调用:
case MotionEvent.ACTION_UP: ... // 计算每个元素中箭头需要旋转的角度 for (...) { ... } delayReset();// 调用 break;
OK,现在可以看看自动重置的效果了:
三、结:
这篇文章就到这里了,下一篇文章会做最后的改动,主要是增加一个功能,然后点击事件的逻辑需要做些修改:
1、加一个设置初始密码的功能
2、让手势单点可以生效
3、自动补充轨迹(例如选中第一排的1位和3位时2位也能自动选中)- Android应用 手势密码的实现(二)
- Android应用 手势密码的实现(一)
- Android应用 手势密码的实现(三)
- Android应用 手势密码的实现(四)
- Android手势密码的实现
- Android手势密码view笔记(二)
- Android招财进宝手势密码的实现
- Android招财进宝手势密码的实现
- Android招财进宝手势密码的实现
- 手势密码(二)
- Android手势密码实现方案
- Android手势密码实现方案
- Android手势密码实现方案
- Android手势密码实现方案
- [Android开发实战]Android手势密码(支付宝手势密码)实现(支持2.x)
- Android应用密码的实现
- Android应用密码的实现
- Android手势(二)
- cpp 4.22
- Android官方MVP架构示例项目解析
- 欢迎使用CSDN-markdown编辑器
- java学习过程中乱记的笔记
- C++动态链接库导出函数或者类
- Android应用 手势密码的实现(二)
- 一个2年Android开发者的18条建议
- WebApi2中action几种返回值
- 模态窗口小结
- C语言字节对齐详解
- Adnroid 简单易用的Log
- AndroidStudio利用android-support-multidex解决65536问题64k问题
- c++笔记(3):函数内联、重载、宏定义、static和extern、存储区域
- C/C++ struct 结构体定义 用法详解