纯android代码实现九宫格手势密码

这几天项目中要加九宫格手势密码,在网上搜了大量资料,大部分都是以图片实现为主,集合部分代码,android实现纯代码九宫格。

好了,不废话了,先上图。

效果大概就是这样,逻辑自己实现,我只上这个自定义控件的代码。

1.    point.Java  点的位置

/**
 * 点位置
 */
public class Point {
 public static int STATE_NORMAL = 0;
 public static int STATE_CHECK = 1; //
 public static int STATE_CHECK_ERROR = 2; // 

 public float x;
 public float y;
 public int state = 0;
 public int index = 0;// 

 public Point() { 

 } 

 public Point(float x, float y, int value) {
  this.x = x;
  this.y = y;
  index = value;
 } 

 public int getColNum() {
  return (index - 1) % 3;
 } 

 public int getRowNum() {
  return (index - 1) / 3;
 } 

}

2.     MathUtil.java   计算两点之间的距离

public class MathUtil {
 /**
  *
  * @param x1
  * @param y1
  * @param x2
  * @param y2
  * @return
  */
 public static double distance(double x1, double y1, double x2, double y2) {
  return Math.sqrt(Math.abs(x1 - x2) * Math.abs(x1 - x2)
    + Math.abs(y1 - y2) * Math.abs(y1 - y2));
 } 

 /**
  *
  * @param x
  * @param y
  * @return
  */
 public static double pointTotoDegrees(double x, double y) {
  return Math.toDegrees(Math.atan2(x, y));
 } 

 public static boolean checkInRound(float sx, float sy, float r, float x,
   float y) {
  return Math.sqrt((sx - x) * (sx - x) + (sy - y) * (sy - y)) < r;
 }
}

3.      LocusPassWordView.java   九宫格自定义控件

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;
import com.example.esop.util.MathUtil;
import com.example.esop.util.Point; 

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask; 

public class LocusPassWordView extends View {
 private float width = 0;
 private float height = 0; 

 //
 private boolean isCache = false;
 //
 private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 

 //
 private Point[][] mPoints = new Point[3][3];
 //
 private float dotRadius = 0;
 //
 private List<Point> sPoints = new ArrayList<Point>();
 private boolean checking = false;
 private long CLEAR_TIME = 1000;
 private int pwdMaxLen = 9;
 private int pwdMinLen = 4;
 private boolean isTouch = true; 

 private Paint arrowPaint;
 private Paint linePaint;
 private Paint selectedPaint;
 private Paint errorPaint;
 private Paint normalPaint;
 private int errorColor = 0xffea0945;
 private int selectedColor = 0xff0596f6;
 private int outterSelectedColor = 0xff8cbad8;
 private int outterErrorColor = 0xff901032;
 private int dotColor = 0xffd9d9d9;
 private int outterDotColor = 0xff929292; 

 public LocusPassWordView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
 } 

 public LocusPassWordView(Context context, AttributeSet attrs) {
  super(context, attrs);
 } 

 public LocusPassWordView(Context context) {
  super(context);
 } 

 @Override
 public void onDraw(Canvas canvas) {
  if (!isCache) {
   initCache();
  }
  drawToCanvas(canvas);
 } 

 private void drawToCanvas(Canvas canvas) {
  boolean inErrorState = false;
  for (int i = 0; i < mPoints.length; i++) {
   for (int j = 0; j < mPoints[i].length; j++) {
    Point p = mPoints[i][j];
    if (p.state == Point.STATE_CHECK) {
     selectedPaint.setColor(outterSelectedColor);
     canvas.drawCircle(p.x, p.y, dotRadius, selectedPaint);
     selectedPaint.setColor(selectedColor);
     canvas.drawCircle(p.x, p.y, dotRadius/4, selectedPaint);
    } else if (p.state == Point.STATE_CHECK_ERROR) {
     inErrorState = true;
     errorPaint.setColor(outterErrorColor);
     canvas.drawCircle(p.x, p.y, dotRadius, errorPaint);
     errorPaint.setColor(errorColor);
     canvas.drawCircle(p.x, p.y, dotRadius/4, errorPaint);
    } else {
     normalPaint.setColor(dotColor);
     canvas.drawCircle(p.x, p.y, dotRadius, normalPaint);
     normalPaint.setColor(outterDotColor);
     canvas.drawCircle(p.x, p.y, dotRadius/4, normalPaint);
    }
   }
  } 

  if (inErrorState) {
   arrowPaint.setColor(errorColor);
   linePaint.setColor(errorColor);
  } else {
   arrowPaint.setColor(selectedColor);
   linePaint.setColor(selectedColor);
  } 

  if (sPoints.size() > 0) {
   int tmpAlpha = mPaint.getAlpha();
   Point tp = sPoints.get(0);
   for (int i = 1; i < sPoints.size(); i++) {
    Point p = sPoints.get(i);
    drawLine(tp, p, canvas, linePaint);
    drawArrow(canvas, arrowPaint, tp, p, dotRadius/4, 38);
    tp = p;
   }
   if (this.movingNoPoint) {
    drawLine(tp, new Point(moveingX, moveingY, -1), canvas, linePaint);
   }
   mPaint.setAlpha(tmpAlpha);
  } 

 } 

 private void drawLine(Point start, Point end, Canvas canvas, Paint paint) {
  double d = MathUtil.distance(start.x, start.y, end.x, end.y);
  float rx = (float) ((end.x-start.x) * dotRadius / 4 / d);
  float ry = (float) ((end.y-start.y) * dotRadius / 4 / d);
  canvas.drawLine(start.x+rx, start.y+ry, end.x-rx, end.y-ry, paint);
 } 

 private void drawArrow(Canvas canvas, Paint paint, Point start, Point end, float arrowHeight, int angle) {
  double d = MathUtil.distance(start.x, start.y, end.x, end.y);
  float sin_B = (float) ((end.x - start.x) / d);
  float cos_B = (float) ((end.y - start.y) / d);
  float tan_A = (float) Math.tan(Math.toRadians(angle));
  float h = (float) (d - arrowHeight - dotRadius * 1.1);
  float l = arrowHeight * tan_A;
  float a = l * sin_B;
  float b = l * cos_B;
  float x0 = h * sin_B;
  float y0 = h * cos_B;
  float x1 = start.x + (h + arrowHeight) * sin_B;
  float y1 = start.y + (h + arrowHeight) * cos_B;
  float x2 = start.x + x0 - b;
  float y2 = start.y + y0 + a;
  float x3 = start.x + x0 + b;
  float y3 = start.y + y0 - a;
  Path path = new Path();
  path.moveTo(x1, y1);
  path.lineTo(x2, y2);
  path.lineTo(x3, y3);
  path.close();
  canvas.drawPath(path, paint);
 } 

 private void initCache() {
  width = this.getWidth();
  height = this.getHeight();
  float x = 0;
  float y = 0; 

  if (width > height) {
   x = (width - height) / 2;
   width = height;
  } else {
   y = (height - width) / 2;
   height = width;
  } 

  int leftPadding = 15;
  float dotPadding = width / 3 - leftPadding;
  float middleX = width / 2;
  float middleY = height / 2; 

  mPoints[0][0] = new Point(x + middleX - dotPadding, y + middleY - dotPadding, 1);
  mPoints[0][1] = new Point(x + middleX, y + middleY - dotPadding, 2);
  mPoints[0][2] = new Point(x + middleX + dotPadding, y + middleY - dotPadding, 3);
  mPoints[1][0] = new Point(x + middleX - dotPadding, y + middleY, 4);
  mPoints[1][1] = new Point(x + middleX, y + middleY, 5);
  mPoints[1][2] = new Point(x + middleX + dotPadding, y + middleY, 6);
  mPoints[2][0] = new Point(x + middleX - dotPadding, y + middleY + dotPadding, 7);
  mPoints[2][1] = new Point(x + middleX, y + middleY + dotPadding, 8);
  mPoints[2][2] = new Point(x + middleX + dotPadding, y + middleY + dotPadding, 9); 

  Log.d("jerome", "canvas width:"+width);
  dotRadius = width / 10;
  isCache = true; 

  initPaints();
 } 

 private void initPaints() {
  arrowPaint = new Paint();
  arrowPaint.setColor(selectedColor);
  arrowPaint.setStyle(Style.FILL);
  arrowPaint.setAntiAlias(true); 

  linePaint = new Paint();
  linePaint.setColor(selectedColor);
  linePaint.setStyle(Style.STROKE);
  linePaint.setAntiAlias(true);
  linePaint.setStrokeWidth(dotRadius / 9); 

  selectedPaint = new Paint();
  selectedPaint.setStyle(Style.STROKE);
  selectedPaint.setAntiAlias(true);
  selectedPaint.setStrokeWidth(dotRadius / 6); 

  errorPaint = new Paint();
  errorPaint.setStyle(Style.STROKE);
  errorPaint.setAntiAlias(true);
  errorPaint.setStrokeWidth(dotRadius / 6); 

  normalPaint = new Paint();
  normalPaint.setStyle(Style.STROKE);
  normalPaint.setAntiAlias(true);
  normalPaint.setStrokeWidth(dotRadius / 9);
 } 

 /**
  *
  *
  * @param index
  * @return
  */
 public int[] getArrayIndex(int index) {
  int[] ai = new int[2];
  ai[0] = index / 3;
  ai[1] = index % 3;
  return ai;
 } 

 /**
  * @param x
  * @param y
  * @return
  */
 private Point checkSelectPoint(float x, float y) {
  for (int i = 0; i < mPoints.length; i++) {
   for (int j = 0; j < mPoints[i].length; j++) {
    Point p = mPoints[i][j];
    if (MathUtil.checkInRound(p.x, p.y, dotRadius, (int) x, (int) y)) {
     return p;
    }
   }
  }
  return null;
 } 

 /**
  *
  */
 private void reset() {
  for (Point p : sPoints) {
   p.state = Point.STATE_NORMAL;
  }
  sPoints.clear();
  this.enableTouch();
 } 

 /**
  *
  *
  * @param p
  * @return
  */
 private int crossPoint(Point p) {
  // reset
  if (sPoints.contains(p)) {
   if (sPoints.size() > 2) {
    //
    if (sPoints.get(sPoints.size() - 1).index != p.index) {
     return 2;
    }
   }
   return 1; //
  } else {
   return 0; //
  }
 } 

 /**
  *
  *
  * @param point
  */
 private void addPoint(Point point) {
  if (sPoints.size() > 0) {
   Point lastPoint = sPoints.get(sPoints.size() - 1);
   int dx = Math.abs(lastPoint.getColNum() - point.getColNum());
   int dy = Math.abs(lastPoint.getRowNum() - point.getRowNum());
   if ((dx > 1 || dy > 1) && (dx == 0 || dy == 0 || dx == dy)) {
//   if ((dx > 1 || dy > 1) && (dx != 2 * dy) && (dy != 2 * dx)) {
    int middleIndex = (point.index + lastPoint.index) / 2 - 1;
    Point middlePoint = mPoints[middleIndex / 3][middleIndex % 3];
    if (middlePoint.state != Point.STATE_CHECK) {
     middlePoint.state = Point.STATE_CHECK;
     sPoints.add(middlePoint);
    }
   }
  }
  this.sPoints.add(point);
 } 

 /**
  * @param
  * @return
  */
 private String toPointString() {
  if (sPoints.size() >= pwdMinLen && sPoints.size() <= pwdMaxLen) {
   StringBuffer sf = new StringBuffer();
   for (Point p : sPoints) {
    sf.append(p.index);
   }
   return sf.toString();
  } else {
   return "";
  }
 } 

 boolean movingNoPoint = false;
 float moveingX, moveingY; 

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //
  if (!isTouch) {
   return false;
  } 

  movingNoPoint = false; 

  float ex = event.getX();
  float ey = event.getY();
  boolean isFinish = false;
  boolean redraw = false;
  Point p = null;
  switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN: //
   //
   if (task != null) {
    task.cancel();
    task = null;
    Log.d("task", "touch cancel()");
   }
   //
   reset();
   p = checkSelectPoint(ex, ey);
   if (p != null) {
    checking = true;
   }
   break;
  case MotionEvent.ACTION_MOVE:
   if (checking) {
    p = checkSelectPoint(ex, ey);
    if (p == null) {
     movingNoPoint = true;
     moveingX = ex;
     moveingY = ey;
    }
   }
   break;
  case MotionEvent.ACTION_UP:
   p = checkSelectPoint(ex, ey);
   checking = false;
   isFinish = true;
   break;
  }
  if (!isFinish && checking && p != null) { 

   int rk = crossPoint(p);
   if (rk == 2) //
   {
    // reset();
    // checking = false; 

    movingNoPoint = true;
    moveingX = ex;
    moveingY = ey; 

    redraw = true;
   } else if (rk == 0) //
   {
    p.state = Point.STATE_CHECK;
    addPoint(p);
    redraw = true;
   }
   // rk == 1 

  } 

  //
  if (redraw) { 

  }
  if (isFinish) {
   if (this.sPoints.size() == 1) {
    this.reset();
   } else if (sPoints.size() < pwdMinLen || sPoints.size() > pwdMaxLen) {
    // mCompleteListener.onPasswordTooMin(sPoints.size());
    error();
    clearPassword();
    Toast.makeText(this.getContext(), "手势密码少于4个点", Toast.LENGTH_SHORT).show();
   } else if (mCompleteListener != null) {
    this.disableTouch();
    mCompleteListener.onComplete(toPointString());
   }
  }
  this.postInvalidate();
  return true;
 } 

 /**
  *
  */
 private void error() {
  for (Point p : sPoints) {
   p.state = Point.STATE_CHECK_ERROR;
  }
 } 

 public void markError() {
  markError(CLEAR_TIME);
 } 

 public void markError(final long time) {
  for (Point p : sPoints) {
   p.state = Point.STATE_CHECK_ERROR;
  }
  this.clearPassword(time);
 } 

 public void enableTouch() {
  isTouch = true;
 } 

 public void disableTouch() {
  isTouch = false;
 } 

 private Timer timer = new Timer();
 private TimerTask task = null; 

 public void clearPassword() {
  clearPassword(CLEAR_TIME);
 } 

 public void clearPassword(final long time) {
  if (time > 1) {
   if (task != null) {
    task.cancel();
    Log.d("task", "clearPassword cancel()");
   }
   postInvalidate();
   task = new TimerTask() {
    public void run() {
     reset();
     postInvalidate();
    }
   };
   Log.d("task", "clearPassword schedule(" + time + ")");
   timer.schedule(task, time);
  } else {
   reset();
   postInvalidate();
  } 

 } 

 //
 private OnCompleteListener mCompleteListener; 

 /**
  * @param mCompleteListener
  */
 public void setOnCompleteListener(OnCompleteListener mCompleteListener) {
  this.mCompleteListener = mCompleteListener;
 } 

 public interface OnCompleteListener { 

  public void onComplete(String password);
 }
}

大概代码就是上面三个类了,保存九宫格密码 有很多种,我使用 SharedPreferences 保存,相信都知道。

下面附上这三个类的源码下载地址:android实现纯代码九宫格

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android手势密码的实现

    一.大致界面介绍: 图1 图2 图3 图4 图1:手势密码绘制界面 [主要是绘制上方的9个提示图标和9个宫格密码图标] 图2:设置手势密码 [监听手势的输入,TouchEvent的事件处理,获取输入的手势密码,同时显示在上方的提示区域] 图3:再绘制一次,两次密码不一致提示界面 [这里在实现的时候,错误提示文字加了"左右晃动的动画",错误路径颜色标记为红色] 图4:校验手势密码,输入的密码错误,给予红色路径+错误文字提示 二.实现思路: 1. 正上方的提示区域,用一个类(LockInd

  • Android仿支付宝手势密码解锁功能

    Starting 创建手势密码可以查看 CreateGestureActivity.java 文件. 登陆验证手势密码可以看 GestureLoginActivity.java 文件. Features 使用了 JakeWharton/butterknife butterknife 使用了 ACache 来存储手势密码 /** * 保存手势密码 */ private void saveChosenPattern(List<LockPatternView.Cell> cells) { byte[

  • Android实现手势密码功能

    本文实例为大家分享了Android实现手势密码功能的具体代码,供大家参考,具体内容如下 首先声明一下,九宫格布局是从网上扒了一个大神写好的,大家在项目中实现的话可以直接把: Drawl,GuestureLockView,Point类直接复制到自己的项目中: 想了解功能的可以仔细看下源码中的这三个类,里面写的也非常详细: 使用GuestureLockView的三个步: 1.初始化布局容器: 2.初始化GuestureLockView; 3.将GuestureLockView添加到布局容器中: 创建

  • Android九宫格手势密码代码设计

    最近因为项目需要用到九宫格密码(也叫手势轨迹密码),特地去学习了一下九宫格密码的实现原来.可能有人认为九宫格密码事例网上到处都有,很多甚至直接拷贝过来就可以运行为什么还要学习呢.还特地写到网上有必要吗?其实写这个目的是为了增强和锻炼自己的语言组织能力.其实如果只是既然是学习就不光是要知道答案(完成效果)更重要的是知道他什么实现. 好了题外话就不多说了,要实现九宫格密码要解决的问题有: 1.给九宫格密码界面布局九个点,即确定每个节点的位置.每个点到上下左右的距离都是相同的.即九个点刚好围成一个正方

  • Android自定义UI手势密码终结版

    之前写过3篇手势密码的demo,不过没有集成到真实的企业项目中,这几天正好领到一个手势密码项目,昨天刚好弄完,今天抽空整理下,目前还没有完善,有一些地方需要更改,不过基本的流程都可以跑通了. 源码下载地址:http://xiazai.jb51.net/201610/yuanma/AndroidGestureLock(jb51.net).rar 先看主界面的入口把.里面有2个button(一个是设置手势密码.一个是校验手势密码) activity_main.xml <RelativeLayout

  • Android自定义UI手势密码简单版

    先看看效果图: ImageLockActivity package com.example.imagelock; import com.example.view.NinePointLineView; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.View; public class ImageLockActivity extends Acti

  • Android自定义控件实现手势密码

    Android手势解锁密码效果图 首先呢想写这个手势密码的想法呢,完全是凭空而来的,然后笔者就花了一天时间弄出来了.本以为这个东西很简单,实际上手的时候发现,还有很多逻辑需要处理,稍不注意就容易乱套.写个UI效果图大约只花了3个小时,但是处理逻辑就处理了2个小时!废话不多说,下面开始讲解.      楼主呢,自己比较自定义控件,什么东西都掌握在自己的手里感觉那是相当不错(对于赶工期的小伙瓣儿们还是别手贱了,非常容易掉坑),一有了这个目标,我就开始构思实现方式.      1.整个自定义控件是继承

  • Android自定义UI手势密码改进版源码下载

    在之前文章的铺垫下,再为大家分享一篇:Android手势密码,附源码下载,不要错过. 源码下载:http://xiazai.jb51.net/201610/yuanma/androidLock(jb51.net).rar 先看第一张图片的布局文件 activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://sc

  • Android手势密码实现实例代码

    一.效果实现 二.实现思路: 1. 正上方的提示区域,用一个类(LockIndicator.java)来实现,自定义view来绘制9个提示图标: 2. 手势密码绘制区域,用一个类(GestureContentView.java)来实现,它继承自ViewGroup里面, 添加9个ImageView来表示图标, 在onLayout()方法中设置它们的位置: 3. 手势路径绘制, 用一个类(GestureDrawline.java)来实现,复写onTouchEvent()方法,在这个方法里面监听Tou

  • Android 简易手势密码开源库详解

    简介 本文介绍一个Android手势密码开源库的使用及实现的详细过程,该开源库主要实现以下几个功能: 支持手势密码的绘制,并支持密码保存功能,解锁时自动比对密码给出结果 封装了绘制密码的方法,比对两次密码是否一致,可以快捷地进行手势密码的设置 可以设置密码输入错误后的重试次数上限 可以自定义不同状态下手势密码图案的颜色 可以自定义手势密码的触摸点数量(n*n) 最近需要用到手势密码解锁功能,找了一些demo感觉用起来都有点麻烦,于是参考一些文章自己造了下轮子,封装了相关的一些方法,使用起来比较便

随机推荐