先来看看效果:

1.九宫格界面实现了密码的绘制,包括:绘制中、绘制不符合要求、绘制成功3个状态

2.绘制过程的监听:绘制错误、绘制成功,以及密码点所对应的密码

3.附上源码(编码:UTF-8,可导入到Android Studio中):点击下载(http://download.csdn.net/detail/fang_guiliang/8449057)

再来看看代码的实现:

第1步:新建自定义属性,在values文件夹下面新建资源文件,命名为:attrs.xml,用于自定义属性,其中的代码如下:

deblcokingMargin:是密码点之间的间距

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="DeblockingDot"><attr name="deblcokingMargin" format="dimension"></attr></declare-styleable>
</resources>

第2步:新建DeblockingDot类继承View,并且实现相应的构造方法,并获取上面自定义属性的值,事实上密码错误成功需要显示的图片也可以按照自定义属性的方法加载到DeblockingDot类中,此处直接加载资源文件:

    public DeblockingDot(Context context) {this(context, null);}public DeblockingDot(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DeblockingDot(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DeblockingDot);final int length = array.getIndexCount();for (int i = 0; i < length; i++) {int attr = array.getIndex(i);switch (attr) {case R.styleable.DeblockingDot_deblcokingMargin:margin = array.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 0,getResources().getDisplayMetrics()));break;}}array.recycle();//回收资源initData();//初始化数据}

intitData()方法中的代码:获取图片资源,创建对象等:

    private Bitmap mDefaultBitmap;//默认状态下的图private Bitmap mErrorBitmap;//错误状态下的图private Bitmap mPressedBitmap;//选中状态下的图private Bitmap mPressedLine;//选中的线private Bitmap mErrorLine;//错误的线private Paint mPaint;//画笔,用于画线和密码状态的private Matrix mMatrix;//矩阵,用于缩放线private ArrayList<Point> pointList;//密码点的集合
    private void initData() {mDefaultBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_default);mErrorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_error);mPressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_pressed);mPressedLine = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);mErrorLine = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);mBitmapR = mDefaultBitmap.getHeight() / 2;mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setAntiAlias(true);//间距必须大于图标的半径margin = margin < mBitmapR ? mBitmapR : margin;pointList = new ArrayList<Point>();mMatrix = new Matrix();}

第3步:需要创建密码点的类:Point,用于保存密码点对应的状态、坐标、所代表的密码,其中还包含几个工具方法,用于计算点和点的距离,手指接触屏幕的点到密码点的距离等,具体代码如下:

    public static class Point {//默认状态public static int STATUS_DEFAULT = 0;//错误状态public static int STATUS_ERROR = 1;//选中状态public static int STATUS_PRESSED = 2;//x轴位置public float x;//y轴位置public float y;//状态public int status;//密码public int password;public Point(float x, float y) {this.x = x;this.y = y;}/*** 判断两个点之间的距离是否小于r** @param pointX 点的x轴* @param pointY 点的y轴* @param mouseX 鼠标的x轴* @param mouseY 鼠标的y轴* @param r* @return*/public static boolean checkPointDistance(float pointX, float pointY, float mouseX, float mouseY, float r) {return Math.sqrt((pointX - mouseX) * (pointX - mouseX) + (pointY - mouseY) * (pointY - mouseY)) < r;}/*** @param a 点a* @param b 点b* @return 两点之间的距离*/public static double distacne(Point a, Point b) {return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));}}

第4步:重写onDraw方法进行绘制,由于需要用到控件的宽高,所以密码点需要在onDraw初始化

private boolean isInit;//是否初始化过点@Overrideprotected void onDraw(Canvas canvas) {if (!isInit) {initPoint();isInit = true;}points2Canvas(canvas);line2Canvas(canvas);}private Point[][] points;//二维数组,存放3行3列的密码点,一共9个值/*** 初始化密码点*/private void initPoint() {float width = getWidth();float height = getHeight();float offsetsX = 0f;//x轴偏移量float offsetsY = 0f;//Y轴偏移量if (height > width) {offsetsY = (height - width) / 2;height = width;} else {offsetsX = (width - height) / 2;width = height;}points = new Point[3][3];float oneX = offsetsX + margin;//第一竖x轴float twoX = offsetsX + width / 2;//第二竖x轴float threeX = offsetsX + width - margin;//第三竖x轴float oneY = offsetsY + margin;//第一行y轴float twoY = offsetsY + height / 2;//第二行y轴float threeY = offsetsY + width - margin;//第三行y轴//第一行points[0][0] = new Point(oneX, oneY);points[0][1] = new Point(twoX, oneY);points[0][2] = new Point(threeX, oneY);//第二行points[1][0] = new Point(oneX, twoY);points[1][1] = new Point(twoX, twoY);points[1][2] = new Point(threeX, twoY);//第三行points[2][0] = new Point(oneX, threeY);points[2][1] = new Point(twoX, threeY);points[2][2] = new Point(threeX, threeY);//为每个点设置对应的密码int password = 0;for (Point[] points : this.points) {for (Point point : points) {point.password = ++password;}}}/*** 画点** @param canvas*/private void points2Canvas(Canvas canvas) {Point point;for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {point = points[i][j];if (point.status == Point.STATUS_DEFAULT) {canvas.drawBitmap(mDefaultBitmap, point.x - mBitmapR, point.y - mBitmapR, mPaint);} else if (point.status == Point.STATUS_PRESSED) {canvas.drawBitmap(mPressedBitmap, point.x - mBitmapR, point.y - mBitmapR, mPaint);} else if (point.status == Point.STATUS_ERROR) {canvas.drawBitmap(mErrorBitmap, point.x - mBitmapR, point.y - mBitmapR, mPaint);}}}}

第5步:重写onTouchEvent方法,监听屏幕,包括手指按下,拖动和离开,在此过程中判断手指经过的位置,同时绘制图案

    @Overridepublic boolean onTouchEvent(MotionEvent event) {mouseX = event.getX();//手指位置xmouseY = event.getY();//手指位置YisFinish = false;isNeedCanvas = false;Point point = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN://手指按下resetPoint();point = checkSelectPoint();if (point != null) {isSelected = true;if (listener != null)listener.onActionDown(true);}break;case MotionEvent.ACTION_MOVE:if (isSelected) {//当第一个点确认后才开始检查其它点point = checkSelectPoint();if (point == null) {//不是目标的点isNeedCanvas = true;}} else {point = checkSelectPoint();if (point != null) {isSelected = true;if (listener != null)listener.onActionDown(true);}}break;case MotionEvent.ACTION_UP:isSelected = false;isFinish = true;break;}//防止重复选中if (!isFinish && isSelected && point != null) {//在绘制过程中检测pointif (!pointList.contains(point)) {point.status = Point.STATUS_PRESSED;pointList.add(point);} else {isNeedCanvas = true;}}// 绘制结束,检测密码是否符合规则if (isFinish) {/*if (pointList.size() == 1) {resetPoint();}*/if (pointList.size() < MIN_POINT_COUNT && pointList.size() > 0) {errorPoint();if (listener != null) {listener.onPointChange(null);}} else {String password = "";for (int i = 0; i < pointList.size(); i++) {password = password + pointList.get(i).password;}if (listener != null) {listener.onPointChange(password);}}}postInvalidate();//重新绘制return true;}/*** 重置点的状态*/public void resetPoint() {for (int i = 0; i < pointList.size(); i++) {pointList.get(i).status = Point.STATUS_DEFAULT;}pointList.clear();}/*** 绘制错误的点*/private void errorPoint() {for (int i = 0; i < pointList.size(); i++) {pointList.get(i).status = Point.STATUS_ERROR;}}/*** 检测鼠标按下是否接近某个点*/private Point checkSelectPoint() {Point point = null;Point tmpPoint = null;for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {tmpPoint = points[i][j];if (Point.checkPointDistance(tmpPoint.x, tmpPoint.y, mouseX, mouseY, mBitmapR)) {point = tmpPoint;}}}return point;}

第6步:画线,其中线的方向即角度是难点,理解好思路就够了,其中线的图标很小,在绘制中需要用到矩阵对其进行平铺拉伸

   /*** 画线** @param canvas*/private void line2Canvas(Canvas canvas) {if (pointList.size() > 0) {Point a = pointList.get(0);Point b;for (int i = 1; i < pointList.size(); i++) {//从第二个点开始,赋给第一个点b = pointList.get(i);line2Canvas(canvas, a, b);a = b;}if (isNeedCanvas) {//需要继续画线条line2Canvas(canvas, a, new Point(mouseX, mouseY));}}}private void line2Canvas(Canvas canvas, Point a, Point b) {float lineLength = (float) Point.distacne(a, b);//需要画的线的长度float degree = getDegree(a, b);canvas.rotate(degree, a.x, a.y);//旋转画布,原点发发生了变化if (a.status == Point.STATUS_PRESSED) {mMatrix.setScale(lineLength / mPressedLine.getWidth(), 1);//设置X轴缩放比例mMatrix.postTranslate(a.x - mErrorLine.getWidth() / 2, a.y - mErrorLine.getHeight() / 2);//矩阵平铺canvas.drawBitmap(mPressedLine, mMatrix, mPaint);} else {mMatrix.setScale(lineLength / mErrorLine.getWidth(), 1);//设置X轴缩放比例mMatrix.postTranslate(a.x - mErrorLine.getWidth() / 2, a.y - mErrorLine.getHeight() / 2);//矩阵平铺canvas.drawBitmap(mErrorLine, mMatrix, mPaint);}canvas.rotate(-degree, a.x, a.y);//恢复画布,恢复原点}/*** 获取线的角度** @param a 点a* @param b 点b* @return 角度*/private float getDegree(Point a, Point b) {float ax = a.x;float ay = a.y;float bx = b.x;float by = b.y;float degress = 0f;if (ax == bx) {//x轴相等,角度为270或者90度if (ay > by) {degress = 270;} else if (ay < by) {degress = 90;}} else if (ay == by) {//y轴相等,角度为0或者180;if (ax > bx) {degress = 180;} else if (ax < bx) {degress = 0;}} else if (ax > bx) {//b在a的左边,90度到270度if (ay < by) {//b在a下,90度到180度degress = 90 + switchDegress(Math.abs(bx - ax), Math.abs(by - ay));} else if (ay > by) {//b在a的下边,180度到270度degress = 270 - switchDegress(Math.abs(bx - ax), Math.abs(by - ay));}} else if (ax < bx) {//b在a的右边,270到90度if (ay > by) {//b在a下边,360到0degress = 270 + switchDegress(Math.abs(bx - ax), Math.abs(by - ay));} else if (ay < by) {//b在a上边,0到90degress = 90 - switchDegress(Math.abs(bx - ax), Math.abs(by - ay));}}return degress;}
/*** 强制转换为角度** @param x x轴* @param y y轴* @return 角度*/private float switchDegress(float x, float y) {return (float) Math.toDegrees(Math.atan2(x, y));}

以上描述了,整个自定义九宫格图案的完成思路,代码也注释清楚了,角度这块可能难理解,暂且这样吧,可以下载源码Demo整体看下,里面实现了密码的监听等,可以直接使用到项目中,有疑问的请留言一同讨论。

附上源码:点击下载(http://download.csdn.net/detail/fang_guiliang/8449057)

九宫格图案解锁、支付宝解锁、微信钱包解锁相关推荐

  1. java实现九宫格解锁_轻松实现Android自定义九宫格图案解锁

    Android实现九宫格图案解锁,自带将图案转化成数字密码的功能,代码如下: LockPatternView.java package com.jackie.lockpattern; import a ...

  2. 九宫锁屏图案有多少种c语言编程,手机九宫格图案解锁问题,编程高手戳进来!...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 数学吧里看到的一个有趣问题,题目描述很简单: 求手机九宫格图案解锁一共有多少种答案.规则大家应该都知道,至少连四个点,最多连九个点,一条直线上的三个点只有 ...

  3. Android实现九宫格图案解锁

    Android实现九宫格图案解锁 前言:自定义了一个九宫格的VIew来绘制九宫格图案,实现了绘制图案解锁的功能. 效果图如下: 1. 第一步 自定义九宫格View. public class Lock ...

  4. 用C语言计算手机的九宫格图案解锁总共能绘出多少种图案

    之前在学校的一个社团招募大一新生时,给出了这个题目: 用程序编写完成九宫格图案解锁总共能绘出多少种图案 需要满足的要求有: 1.至少经过四个点: 2.不能重复经过同一个点: 3.路径上的中间点不能跳过 ...

  5. 解锁来逗微信编辑器隐藏功能

    来逗编辑器更名全新上线,很多小伙伴还不是很了解新版来逗编辑器有哪些功能,下面给大家解锁来逗微信编辑器的隐藏功能. 新版来逗编辑器对于更名前的豆子编辑器,页面上有了简单的调整,去掉左侧栏目,加大编辑区, ...

  6. android解锁界面分析,Android 7.0 锁屏解锁之向上滑动显示解锁界面分析

    Android 7.0 锁屏解锁之向上滑动显示解锁界面分析 by jing.chen 锁屏的解锁操作是在锁屏界面向上滑动实现的,通过向上滑动调出解锁界面(如图案.PIN.密码解锁界面),在解锁界面输入 ...

  7. 苹果手机投影_苹果12pro有没有指纹解锁 带屏下指纹解锁具体说明

    下面是苹果12pro指纹解锁相关介绍.苹果从全面屏手机开始就取消了指纹解锁,从而使用了面部解锁,但是最近安卓手机很流行屏幕指纹解锁.那最新的苹果12pro有没有指纹解锁?不清楚的朋友快来看看这篇教程吧 ...

  8. 元气骑士没有手柄怎么解锁机器人_机器人怎么解锁(元气骑士机器人)

    第一个人物是游戏自带的:科学家威尔逊.不需解锁 第二个人物是火女:薇洛.解锁条件:生存8天后死亡解锁. 第三个人物:大力士沃尔夫冈.解锁条件:生存16天后解锁. 第四个人物:鬼女温蒂.解锁条件:没有确 ...

  9. h5页 点击返回时关闭_在微信、支付宝、百度钱包实现点击返回按钮关闭当前页面和窗口...

    最近在使用微信.支付宝.百度钱包实现网页支付,对支付成功将自动关闭页面,对于支付失败,将显示错误信息.当在错误页面的时候,点击返回 或者Android物理按键上一步的时候,将关闭页面. 在微信.支付宝 ...

最新文章

  1. 海天学院的打造IT人才讲座准备
  2. android android:process=,关于android:Android-appprocess的使用
  3. 输入一个正整数,求它各位数的数字之和
  4. Orchard Core 1.0.0 正式发布!
  5. ruby三元操作符_在Ruby中使用操作符将元素添加到数组实例中
  6. 补习系列(1)-springboot项目基础搭建课
  7. ubuntu18.04 ROS melodic—创建简单的机器人模型smartcar
  8. 《创意特训营——30天超级灵感唤醒术》—第1章1.6节小结
  9. 2步判断晶体管工作状态
  10. NUAAccst计算机网络第四章网络层复习
  11. 大厂面试必问!疯狂Java讲义第五版pdf在线阅读
  12. 迁移学习Transfer Learning
  13. Excel工作表事件(1)
  14. 深入理解搜索引擎-排序算法
  15. Nginx 局域网内互传文件
  16. wps打印错误未定义书签怎么解决_word文档打印时候目录出现错:未定义书签,在wps里怎么修改?...
  17. (第三天)磁盘分区----LVE逻辑卷
  18. 微信小程序:去水印工具微信小程序源码
  19. SafetyNet 漏洞rootutils 利用
  20. ​华为麒麟1020首曝光;全球首款 5G 扩展现实平台发布;英特尔将开拓“全硅”市场;京东周伯文掌舵,申元庆出局……...

热门文章

  1. 朋友问我,斗破苍穹中到底出现了多少次“恐怖如斯”?
  2. Java进阶——注解
  3. 牛客观察 | 大厂疯狂招人背后: 中小企业要躺平“捡漏”吗?
  4. 华盛顿市的布局,也属于风水
  5. Mstar 编译器的搭建
  6. 家族关系查询系统程序设计算法思路_数据结构课程设计(家族关系查询系统)..doc...
  7. Alpha、Beta、RC、GA、RTW版本
  8. windows做时间服务器,linux和windows时间同步
  9. G1的mixed gc详细过程
  10. 基于apache-jena的知识问答