九宫格图案解锁、支付宝解锁、微信钱包解锁 您所在的位置:网站首页 支付宝怎么设置图案锁 九宫格图案解锁、支付宝解锁、微信钱包解锁

九宫格图案解锁、支付宝解锁、微信钱包解锁

2024-07-10 18:45| 来源: 网络整理| 查看: 265

 先来看看效果:

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

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

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

再来看看代码的实现:

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

deblcokingMargin:是密码点之间的间距

第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 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(); 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;//是否初始化过点 @Override protected 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方法,监听屏幕,包括手指按下,拖动和离开,在此过程中判断手指经过的位置,同时绘制图案

@Override public boolean onTouchEvent(MotionEvent event) { mouseX = event.getX();//手指位置x mouseY = event.getY();//手指位置Y isFinish = 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) {//在绘制过程中检测point if (!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到0 degress = 270 + switchDegress(Math.abs(bx - ax), Math.abs(by - ay)); } else if (ay < by) {//b在a上边,0到90 degress = 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)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

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