Android 手势密码锁 您所在的位置:网站首页 手势密码app Android 手势密码锁

Android 手势密码锁

2023-06-21 11:05| 来源: 网络整理| 查看: 265

一:简介

现在有很多银行类APP、涉及到支付类的APP都集成了指纹、手势等二次验证功能,从而使APP获得更高的安全性。今天我们就来分析一下手势密码锁功能的具体实现。

二:源码源码Demo获取方法

关注 【网罗开发】微信公众号,回复【90】便可领取。网罗天下方法,方便你我开发,所有文档会持续更新,欢迎关注一起成长!

三:demo源码分析

网上也不乏有一些手势密码的介绍,但是大多是使用第三方库,今天和大家介绍的是通过继承ViewGroup和View实现的原生手势密码锁。

项目文件

1.逻辑代码类分析

页面逻辑主要通过手势密码容器类(GestureContentView)、手势密码路径绘制类(GestureDrawline)、手势密码图案提示类(LockIndicator)三个类来实现。核心代码如下:

package demo.gesturepsd.gesturepsd_android.widget; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import demo.gesturepsd.gesturepsd_android.R; import demo.gesturepsd.gesturepsd_android.common.AppUtil; import demo.gesturepsd.gesturepsd_android.entity.GesturePoint; import demo.gesturepsd.gesturepsd_android.widget.GestureDrawline.GestureCallBack; import java.util.ArrayList; import java.util.List; /** * 手势密码容器类 * */ public class GestureContentView extends ViewGroup { private int baseNum = 6; private int[] screenDispaly; /** * 每个点区域的宽度 */ private int blockWidth; /** * 声明一个集合用来封装坐标集合 */ private List 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(); 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); } }

2.页面交互实现分析

设置手势密码页面(GestureEditActivity)

通过设置手势路径转换成数字密码,并通过SharedPreferences存储起来,代码如下:

package demo.gesturepsd.gesturepsd_android; import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Html; import android.text.TextUtils; import android.util.Log; 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 demo.gesturepsd.gesturepsd_android.widget.GestureContentView; import demo.gesturepsd.gesturepsd_android.widget.GestureDrawline.GestureCallBack; import demo.gesturepsd.gesturepsd_android.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 static final String fileName = "logintext";//定义保存的文件的名称 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("最少链接4个点, 请重新输入")); 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(); Log.i("charge password", mFirstPassword); SharedPreferences share = getSharedPreferences(fileName, MODE_PRIVATE); SharedPreferences.Editor editor = share.edit(); editor.putString("psdtype", mFirstPassword); editor.commit(); mGestureContentView.clearDrawlineState(0L); GestureEditActivity.this.finish(); } else { mTextTip.setText(Html.fromHtml("与上一次绘制不一致,请重新绘制")); // 左右移动动画 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; } }

校验手势密码页面(GestureVerifyActivity)

通过SharedPreferences获取到设置页面存储的密码与校验输入的密码进行对比,校验密码是否正确,源码如下:

package demo.gesturepsd.gesturepsd_android; import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; import android.text.Html; import android.text.TextUtils; 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; import demo.gesturepsd.gesturepsd_android.widget.GestureContentView; import demo.gesturepsd.gesturepsd_android.widget.GestureDrawline.GestureCallBack; /** * * 手势绘制/校验界面 * */ 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 static final String fileName = "logintext";//定义保存的文件的名称 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); SharedPreferences share = super.getSharedPreferences(fileName, MODE_PRIVATE); String psdtype = share.getString("psdtype", null); // 初始化一个显示各个点的viewGroup mGestureContentView = new GestureContentView(this, true, psdtype, 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("密码错误")); // 左右移动动画 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; } } }

主页面(MainActivity)

主页面是设置手势密码和校验手势密码的两个按钮,源码比较简单,不做展示。

四:Demo 截图

设置手势密码

校验手势密码



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有