Android APP数字解锁实例详解

Android APP数字上锁

最近抽时间做了下数字解锁的功能,手机有数字解锁,App也可以做到,避免某些应用隐私泄漏,一下就是实现效果图:

序言:这两天老大给了个任务,说是做一个仿ios的数字锁屏界面,心想着这种东西网上应该有挺多的,然后就先百度了一把,谁知道案例好像少的可怜,然后带着怀疑的心态去下载了千辛万苦找到的“源码”,看里面写的,然后自己有点眉目了,就自己借着“源码”的思路自己实现了一把,见上图。

思路:

这里我们可以看成两部分,一部分是上面的输入的,另一部分是底部的按键。
先来看上面那部分,我们可以看成是TextView,然后响应下面按键的动作。下面这部分,图中的每个按钮都需要自己画出来,难点就是根据第一个按键的坐标(第一个坐标我们初始化)算出每个按键的坐标,然后根据手指的触摸屏事件来判断点击的是哪个按键

接下来我们来看核心代码:

输入框部分:

public class PasswordTextView extends TextView{
 private final String sing = "*";//密文显示的内容
 private String content = "";//显示的内容
 //文本改变事件回调接口
 private OnTextChangedListener onTextChangedListener;
 /**
  * Handler线程对象,用来更新密码框的显示内容
  * 实现将输入的内容显示为密文
  */
 private Handler handler = new Handler(){
  public void handleMessage(android.os.Message msg) {
   //密文显示
   PasswordTextView.this.setText(sing);
   //回调改变事件接口
   if(onTextChangedListener != null){
    onTextChangedListener.textChanged(content);
   }
  };
 };

 /**
  * 构造方法
  * @param context
  * @param attrs
  */
 public PasswordTextView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 /**
  * 设置文本改变事件监听
  * @param onTextChangedListener
  */
 public void setOnTextChangedListener(OnTextChangedListener onTextChangedListener){
  this.onTextChangedListener = onTextChangedListener;
 }

 /**
  * 设置密码框显示的内容
  * @param text
  */
 public void setTextContent(String text){
  //获得输入的内容
  this.content = text;
  if(!TextUtils.isEmpty(text)){
   handler.sendEmptyMessage(0);//向Handler发送消息
  }else{
   this.setText("");
  }
 }

 /**
  * 获取显示的内容
  * @return
  */
 public String getTextContent(){
  return content;
 }

 /**
  * 文本改变事件接口
  */
 public interface OnTextChangedListener{
  /**
   * 密码框文本改变时调用
   * @param content
   */
  public void textChanged(String content);
 }
}

下面按键部分

public class NumericK eyboard extends View {
 private int screen_width = 0;// 屏幕的宽度
 private float first_x = 0;// 绘制1的x坐标
 private float first_y = 0;// 绘制1的y坐标
 private float[] xs = new float[3];//声明数组保存每一列的圆心横坐标
 private float[] ys = new float[4];//声明数组保存每一排的圆心纵坐标
 private float circle_x, circle_y;//点击处的圆心坐标
 private int number = -1;//点击的数字
 private OnNumberClick onNumberClick;//数字点击事件
 /*
  * 判断刷新数据
  * -1 不进行数据刷新
  * 0 按下刷新
  * 1 弹起刷新
  */
 private int type = -1;

 /**
  * 构造方法
  *
  * @param context
  */
 public NumericKeyboard(Context context) {
  super(context);
  initData(context);// 初始化数据
 }

 public NumericKeyboard(Context context, AttributeSet attrs) {
  super(context, attrs);
  initData(context);// 初始化数据
 }

 /**
  * 设置数字点击事件
  *
  * @param onNumberClick
  */
 public void setOnNumberClick(OnNumberClick onNumberClick) {
  this.onNumberClick = onNumberClick;
 }

 // 初始化数据
 private void initData(Context context) {
  // 获取屏幕的宽度
  screen_width = SystemUtils.getSystemDisplay(context)[0];
  // 获取绘制1的x坐标
  first_x = screen_width / 4;
  // 获取绘制1的y坐标
  first_y = (SystemUtils.getSystemDisplay(context)[1] - SystemUtils.getSystemDisplay(context)[1] / 3) / 4;
  //添加每一排的横坐标
  xs[0] = first_x + 10;
  xs[1] = first_x * 2 + 10;
  xs[2] = first_x * 3 + 10;
  //添加每一列的纵坐标
  ys[0] = 40 + first_y - 15;
  ys[1] = 40 + first_y + first_x - 15;
  ys[2] = 40 + first_y + first_x * 2 - 15;
  ys[3] = 40 + first_y + first_x * 3 - 15;
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  // 创建画笔对象
  Paint paint = new Paint();
  paint.setColor(Color.BLACK);// 设置画笔颜色
  paint.setTextSize(40);// 设置字体大小
  paint.setStrokeWidth(2);
  // 绘制文本,注意是从坐标开始往上绘制
  // 这里较难的就是算坐标
  // 绘制第一排1,2,3
  canvas.drawText("1", first_x, 40 + first_y, paint);
  canvas.drawText("2", first_x * 2, 40 + first_y, paint);
  canvas.drawText("3", first_x * 3, 40 + first_y, paint);
  // 绘制第2排4,5,6
  canvas.drawText("4", first_x, 40 + first_y + first_x, paint);
  canvas.drawText("5", first_x * 2, 40 + first_y + first_x, paint);
  canvas.drawText("6", first_x * 3, 40 + first_y + first_x, paint);
  // 绘制第3排7,8,9
  canvas.drawText("7", first_x, 40 + first_y + first_x * 2, paint);
  canvas.drawText("8", first_x * 2, 40 + first_y + first_x * 2, paint);
  canvas.drawText("9", first_x * 3, 40 + first_y + first_x * 2, paint);
  // 绘制第4排0
  canvas.drawText("0", first_x * 2, 40 + first_y + first_x * 3, paint);
  //为每一个数字绘制一个圆
  paint.setColor(Color.WHITE);//设置画笔颜色
  paint.setAntiAlias(true);//设置抗锯齿
  //设置绘制空心圆
  paint.setStyle(Paint.Style.STROKE);
  //依次绘制第一排的圆
  canvas.drawCircle(first_x + 10, 40 + first_y - 15, 70, paint);
  canvas.drawCircle(first_x * 2 + 10, 40 + first_y - 15, 70, paint);
  canvas.drawCircle(first_x * 3 + 10, 40 + first_y - 15, 70, paint);
  //依次绘制第2排的圆
  canvas.drawCircle(first_x + 10, 40 + first_y + first_x - 15, 70, paint);
  canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x - 15, 70, paint);
  canvas.drawCircle(first_x * 3 + 10, 40 + first_y + first_x - 15, 70, paint);
  //依次绘制第3排的圆
  canvas.drawCircle(first_x + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
  canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
  canvas.drawCircle(first_x * 3 + 10, 40 + first_y + first_x * 2 - 15, 70, paint);
  //绘制最后一个圆
  canvas.drawCircle(first_x * 2 + 10, 40 + first_y + first_x * 3 - 15, 70, paint);

  //判断是否点击数字(点击数字产生的渐变效果)
  if (circle_x > 0 && circle_y > 0) {
   if (type == 0) {//按下刷新
    paint.setColor(Color.WHITE);//设置画笔颜色
    paint.setStyle(Paint.Style.FILL_AND_STROKE);//按下的时候绘制实心圆
    canvas.drawCircle(circle_x, circle_y, 70, paint);//绘制圆
   } else if (type == 1) {//弹起刷新
    paint.setColor(Color.WHITE);//设置画笔颜色
    paint.setStyle(Paint.Style.STROKE);//弹起的时候再绘制空心圆
    canvas.drawCircle(circle_x, circle_y, 70, paint);//绘制圆
    //绘制完成后,重置
    circle_x = 0;
    circle_y = 0;
   }
  }
 }

 /**
  * 获取触摸点击事件
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //事件判断
  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN://按下
    //判断点击的坐标位置
    float x = event.getX();//按下时的X坐标
    float y = event.getY();//按下时的Y坐标
    //判断点击的是哪一个数字圆
    handleDown(x, y);
    return true;
   case MotionEvent.ACTION_UP://弹起
    type = 1;//弹起刷新
    invalidate();//刷新界面
    //返回点击的数字
    if (onNumberClick != null && number != -1) {
     onNumberClick.onNumberReturn(number);
    }
    setDefault();//恢复默认
    //发送辅助事件
    sendAccessEvent(R.string.numeric_keyboard_up);
    return true;
   case MotionEvent.ACTION_CANCEL://取消
    //恢复默认值
    setDefault();
    return true;
  }
  return false;
 }

 /*
  * 恢复默认值
  */
 private void setDefault() {
  circle_x = 0;
  circle_y = 0;
  type = -1;
  number = -1;
  sendAccessEvent(R.string.numeric_keyboard_cancel);
 }

 /*
  * 设置辅助功能描述
  */
 private void sendAccessEvent(int resId) {
  //设置描述
  setContentDescription(getContext().getString(resId));
  //发送辅助事件
  sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
  setContentDescription(null);
 }

 /*
  * 判断点击的是哪一个数字圆
  */
 private void handleDown(float x, float y) {
  //判断点击的是那一列的数据
  if (xs[0] - 70 <= x && x <= xs[0] + 70) {//第一列
   //获取点击处的圆心横坐标
   circle_x = xs[0];
   //判断点击的是哪一排
   if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[0];
    number = 1;//设置点击的数字
   } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[1];
    number = 4;//设置点击的数字
   } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[2];
    number = 7;//设置点击的数字
   }
  } else if (xs[1] - 70 <= x && x <= xs[1] + 70) {//第2列
   //获取点击处的圆心横坐标
   circle_x = xs[1];
   //判断点击的是哪一排
   if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[0];
    number = 2;//设置点击的数字
   } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[1];
    number = 5;//设置点击的数字
   } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[2];
    number = 8;//设置点击的数字
   } else if (ys[3] - 70 <= y && ys[3] + 70 >= y) {//第4排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[3];
    number = 0;//设置点击的数字
   }
  } else if (xs[2] - 70 <= x && x <= xs[2] + 70) {//第3列
   //获取点击处的圆心横坐标
   circle_x = xs[2];
   //判断点击的是哪一排
   if (ys[0] - 70 <= y && ys[0] + 70 >= y) {//第1排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[0];
    number = 3;//设置点击的数字
   } else if (ys[1] - 70 <= y && ys[1] + 70 >= y) {//第2排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[1];
    number = 6;//设置点击的数字
   } else if (ys[2] - 70 <= y && ys[2] + 70 >= y) {//第3排
    //获取点击的数字圆的圆心纵坐标
    circle_y = ys[2];
    number = 9;//设置点击的数字
   }
  }
  sendAccessEvent(R.string.numeric_keyboard_down);
  type = 0;//按下刷新
  //绘制点击时的背景圆
  invalidate();
 }

 /**
  * 数字点击事件
  */
 public interface OnNumberClick {
  /**
   * 返回点击的数字
   *
   * @param number
   */
  public void onNumberReturn(int number);
 }
}

上面说了,难点在于计算按键的位置,在这里我是根据我下载的demo里面的计算方式相应的修改了,如果不明白android屏幕坐标系的同学请看下面的文章:

参考:

android坐标系详解

Github下载地址:DEMO下载

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • android 九宫格滑动解锁开机实例源码学习

    效果图由于网站占时不能上传,以后补上. NinePointLineView.java 复制代码 代码如下: package org.demo.custon_view; import org.demo.utils.MLog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; imp

  • Android指纹解锁方法解析

    我先说说这两种的方式的不同之处吧 第一种: 在调动成功之后 不会让你指纹解锁 而是调转到当初你设置指纹解锁时的 手势解锁页面 第二种: 在调动成功之后,是进行指纹解锁 不调转 你直接把手指放到金属感应环 上面进行指纹验证 大家可以根据需求 自行选择 ok 那就亮代码了 第一种: xml 布局: 一个 文本显示 一个按钮(不解释) MainActivity.java源码 public class MainActivity extends FragmentActivity { Fingerprint

  • 轻松实现安卓(Android)九宫格解锁

    效果图 思路 首先我们来分析一下实现九宫格解锁的思路:当用户的手指触摸到某一个点时,先判断该点是否在九宫格的某一格范围之内,若在范围内,则该格变成选中的状态:之后用户手指滑动的时候,以该格的圆心为中心,用户手指为终点,两点连线.最后当用户手指抬起时,判断划过的九宫格密码是否和原先的密码匹配. 大致的思路流程就是上面这样的了,下面我们可以来实践一下. Point 类 我们先来创建一个 Point 类,用来表示九宫格锁的九个格子.除了坐标 x ,y 之外,还有三种模式:正常模式.按下模式和错误模式.

  • android滑动解锁震动效果的开启和取消

    如果我们需要根据设置中的触摸震动开关来开启和取消滑动解锁的震动效果,就需要做以下修改了. 在LockScreen.java类中的LockScreen方法中的 复制代码 代码如下: else if (mUnlockWidget instanceof MultiWaveView) {            MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget; multiWaveView.setVibrateEnabled(Setti

  • Android实现九宫格解锁的方法

    相信大家都有使用九宫格解锁,比如在设置手机安全项目中,可以使用九宫格解锁,提高安全性,以及在使用支付功能的时候,为了提高安全使用九宫锁,今天就为大家介绍Android实现九宫格的方法,分享给大家供大家参考.具体如下: 运行效果截图如下: 具体代码如下: 布局文件如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas

  • Android手机屏幕敲击解锁功能代码

    1.前言 现在市面上有不少Android手机支持敲击屏幕解锁,敲击屏幕解锁是一项很实用的功能,但一来只支持敲击屏幕,二来只能用于解锁或锁屏,再者我们应用层的开发者切不进去,完全无法玩起来.开发者,开发者,我们既然身为开发者何不搞点大新闻,那么这次我来教教各位如何用代码来实现手机的敲击识别,听起来是不是很有趣,有些跃跃欲试呢.事实上在ios上已经有实现这个功能的应用:Knock,一款敲击来解锁Mac电脑的应用,售价4.99美元,约为33人民币.有时候真想去做ios开发,可以开心的为自己的应用定价,

  • Android仿手机QQ图案解锁功能

    本文实例为大家分享了Android仿手机QQ图案解锁的具体代码,供大家参考,具体内容如下 ps:请不要再问我,为什么导入之后会乱码了. 其实,代码基本上都是从原生系统中提取的:LockPatternView.加密工具类,以及解锁逻辑等,我只是稍作修改,大家都知道,原生系统界面比较丑陋,因此,我特意把QQ的apk解压了,从中拿了几张图案解锁的图片,一个简单的例子就这样诞生了. 好了,废话不多说,我们来看看效果(最后两张是最新4.4系统,炫一下,呵呵): 1.最关健的就是那个自定义九宫格View,代

  • 轻松实现Android自定义九宫格图案解锁

    Android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下: LockPatternView.java package com.jackie.lockpattern; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Point; import android.text.TextUtils; i

  • Android唤醒、解锁屏幕代码实例

    解锁.唤醒屏幕用到KeyguardManager,KeyguardLock,PowerManager,PowerManager.WakeLock   所需权限: 复制代码 代码如下: <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /&

  • Android指纹解锁示例代码

    Android6.0及以上系统支持指纹识别解锁功能:项目中用到,特此抽离出来,备忘. 功能是这样的:在用户将app切换到后台运行(超过一定的时长,比方说30秒),再进入程序中的时候就会弹出指纹识别的界面.用户输入指纹,解锁成功.指纹识别的模块其实很简单啦,google的api已经封装好了,我们只需要学会调用就ok了. 思路: 在用户将程序切换到后台的时候需要有一个方法计时,这样的方法写在哪里呢,对,要写在service中.在Activity中开启服务: Intent intent = new I

随机推荐