Android 图案解锁
首先还是看效果图。
图案解锁的功能在许多应用中都有用过,它比起数字解锁,带给用户的体验要好,今天就来一步一步实现这个功能。
一、初始化
初始化放在onDraw方法中,因为onDraw方法在绘制过程中会执行多次,我们设置一个标量isInit,使初始化只执行一次。
@Overrideprotected void onDraw(Canvas canvas) {if (!isInit) {init();}}private void init() {pressPaint.setColor(Color.YELLOW);pressPaint.setStrokeWidth(10);errorPaint.setColor(Color.RED);errorPaint.setStrokeWidth(10);int width = getWidth();int height = getHeight();int offset = Math.abs(width - height) / 2;int offsetX, offsetY;int space;if (width > height) //横屏{space = height / 4;offsetX = offset;offsetY = 0;} else {space = width / 4;offsetX = 0;offsetY = offset;}points[0][0] = new Point(offsetX + space, offsetY + space);points[0][1] = new Point(offsetX + space * 2, offsetY + space);points[0][2] = new Point(offsetX + space * 3, offsetY + space);points[1][0] = new Point(offsetX + space, offsetY + space * 2);points[1][1] = new Point(offsetX + space * 2, offsetY + space * 2);points[1][2] = new Point(offsetX + space * 3, offsetY + space * 2);points[2][0] = new Point(offsetX + space, offsetY + space * 3);points[2][1] = new Point(offsetX + space * 2, offsetY + space * 3);points[2][2] = new Point(offsetX + space * 3, offsetY + space * 3);normalBitap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);pressBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.press);errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.error);bitmapR = normalBitap.getWidth() / 2;isInit = true;}
二、绘制九个点
绘制前我们先需要确定这九个点的位置,为了适应手机屏的横竖屏切换,我们把这九个点的位置控制在屏幕最短长度范围内,也就是竖屏时我们以手机宽度为准,横屏时我们以手机的高度为准。然后以这个长度确定一个正方形区域,在这个正方形区域内画出这九个点并均匀分布,点的位置已在上面的初始化工作中计算好了,下面就直接绘制了。
private void drawPoint(Canvas canvas) {for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[1].length; j++) {Point point = points[i][j];if (point.state == Point.STATE_NORMAL) {canvas.drawBitmap(normalBitap, point.x - bitmapR, point.y - bitmapR, pointPaint);} else if (point.state == Point.STATE_PRESS) {canvas.drawBitmap(pressBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);} else {canvas.drawBitmap(errorBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);}}}}
这里需要注意画笔绘制的起始点和点所在的中心点有所偏差,所以代码中我们横纵坐标都减去了点的半径长度(bitmapR)。
三、记录手指的绘制
@Overridepublic boolean onTouchEvent(MotionEvent event) {
// super.onTouchEvent(event);mouseX = event.getX();mouseY = event.getY();int[] ij;int i, j;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:resetPoint();ij = getSelectPoint();if (ij != null) {isDraw = true;i = ij[0];j = ij[1];points[i][j].state = Point.STATE_PRESS;pressedPoints.add(points[i][j]);passList.add(i * points.length + j);}break;case MotionEvent.ACTION_MOVE:if (isDraw) {ij = getSelectPoint();if (ij != null) {i = ij[0];j = ij[1];//同一个点不能再添加到pressedPoints中if (!pressedPoints.contains(points[i][j])) {points[i][j].state = Point.STATE_PRESS;pressedPoints.add(points[i][j]);passList.add(i * points.length + j);}}}break;case MotionEvent.ACTION_UP:isDraw = false;break;}invalidate();return true;}
每次重新绘制前都重置所有数据
public void resetPoint() {pressedPoints.clear();passList.clear();for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[0].length; j++) {points[i][j].state = Point.STATE_NORMAL;}}invalidate();}
判断手指划过的地方是否是图案中的某个点
private int[] getSelectPoint() {Point pMouse = new Point(mouseX, mouseY);System.out.println("bitmapR:" + bitmapR);for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[0].length; j++) {if (points[i][j].distance(pMouse) < bitmapR) {int[] result = new int[2];result[0] = i;result[1] = j;return result;}}}return null;}
返回的数组中记录点的坐标位置
手指滑动过程中,还需要不断的画线,此时onDraw方法是这样的:
@Overrideprotected void onDraw(Canvas canvas) {if (!isInit) {init();}//画点drawPoint(canvas);//有点后,开始画线if (pressedPoints.size() > 0) {Point a = pressedPoints.get(0);for (int i = 0; i < pressedPoints.size(); i++) {Point b = pressedPoints.get(i);drawLine(canvas, a, b);a = b;}if (isDraw) {drawLine(canvas, a, new Point(mouseX, mouseY));}}}
画线的方法:
private void drawLine(Canvas canvas, Point a, Point b) {if (a.state == Point.STATE_PRESS) {canvas.drawLine(a.x, a.y, b.x, b.y, pressPaint);} else if (a.state == Point.STATE_ERROR) {canvas.drawLine(a.x, a.y, b.x, b.y, errorPaint);}}
四、添加回调监听接口
public interface OnDrawFinishedListener {boolean onDrawFinished(List<Integer> passList);}private OnDrawFinishedListener onDrawFinishedListener;public void setOnDrawFinishedListener(OnDrawFinishedListener onDrawFinishedListener) {this.onDrawFinishedListener = onDrawFinishedListener;}
我们在手势抬起时调用这个监听方法,onTouchEvent(MotionEvent event)方法中:
case MotionEvent.ACTION_UP:boolean valid = false;if (onDrawFinishedListener != null && isDraw) {valid = onDrawFinishedListener.onDrawFinished(passList);
// onDrawFinishedListener.onDrawFinished(passList);}
// if (passList.size() <= 3) {// valid = false;
// }else {// valid = true;
// }if (!valid) {for (Point p : pressedPoints) {p.state = Point.STATE_ERROR;}}isDraw = false;break;
到这里就完成了图案解锁的自定义View。
在Activity中使用
GestureView myView = (GestureView) findViewById(R.id.view);myView.setOnDrawFinishedListener(new GestureView.OnDrawFinishedListener() {@Overridepublic boolean onDrawFinished(List<Integer> passList) {boolean flag = false;if (passList.size() <= 3) {Toast.makeText(GestureActivity.this, "图案绘制有误!", Toast.LENGTH_SHORT).show();flag = false;}else {Toast.makeText(GestureActivity.this, "图案绘制完成!", Toast.LENGTH_SHORT).show();flag = true;}return flag;}});
最后附上GestureView的完整代码。
public class GestureView extends View {private boolean isInit; //是否初始化private Point[][] points = new Point[3][3];private Paint pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private Paint pressPaint = new Paint();private Paint errorPaint = new Paint();private Bitmap normalBitap, pressBitmap, errorBitmap;private int bitmapR;private boolean isDraw;private ArrayList<Point> pressedPoints = new ArrayList<>();private ArrayList<Integer> passList = new ArrayList<>(); //记录所滑过的点的位置,第几个点,以便后续验证public GestureView(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onDraw(Canvas canvas) {if (!isInit) {init();}//画点drawPoint(canvas);//有点后,开始画线if (pressedPoints.size() > 0) {Point a = pressedPoints.get(0);for (int i = 0; i < pressedPoints.size(); i++) {Point b = pressedPoints.get(i);drawLine(canvas, a, b);a = b;}if (isDraw) {drawLine(canvas, a, new Point(mouseX, mouseY));}}}private void drawLine(Canvas canvas, Point a, Point b) {if (a.state == Point.STATE_PRESS) {canvas.drawLine(a.x, a.y, b.x, b.y, pressPaint);} else if (a.state == Point.STATE_ERROR) {canvas.drawLine(a.x, a.y, b.x, b.y, errorPaint);}}private void drawPoint(Canvas canvas) {for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[1].length; j++) {Point point = points[i][j];if (point.state == Point.STATE_NORMAL) {canvas.drawBitmap(normalBitap, point.x - bitmapR, point.y - bitmapR, pointPaint);} else if (point.state == Point.STATE_PRESS) {canvas.drawBitmap(pressBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);} else {canvas.drawBitmap(errorBitmap, point.x - bitmapR, point.y - bitmapR, pointPaint);}}}}public void resetPoint() {pressedPoints.clear();passList.clear();for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[0].length; j++) {points[i][j].state = Point.STATE_NORMAL;}}invalidate();}private void init() {pressPaint.setColor(Color.YELLOW);pressPaint.setStrokeWidth(10);errorPaint.setColor(Color.RED);errorPaint.setStrokeWidth(10);int width = getWidth();int height = getHeight();int offset = Math.abs(width - height) / 2;int offsetX, offsetY;int space;if (width > height) //横屏{space = height / 4;offsetX = offset;offsetY = 0;} else {space = width / 4;offsetX = 0;offsetY = offset;}points[0][0] = new Point(offsetX + space, offsetY + space);points[0][1] = new Point(offsetX + space * 2, offsetY + space);points[0][2] = new Point(offsetX + space * 3, offsetY + space);points[1][0] = new Point(offsetX + space, offsetY + space * 2);points[1][1] = new Point(offsetX + space * 2, offsetY + space * 2);points[1][2] = new Point(offsetX + space * 3, offsetY + space * 2);points[2][0] = new Point(offsetX + space, offsetY + space * 3);points[2][1] = new Point(offsetX + space * 2, offsetY + space * 3);points[2][2] = new Point(offsetX + space * 3, offsetY + space * 3);normalBitap = BitmapFactory.decodeResource(getResources(), R.drawable.normal);pressBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.press);errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.error);bitmapR = normalBitap.getWidth() / 2;isInit = true;}float mouseX, mouseY;@Overridepublic boolean onTouchEvent(MotionEvent event) {
// super.onTouchEvent(event);mouseX = event.getX();mouseY = event.getY();int[] ij;int i, j;switch (event.getAction()) {case MotionEvent.ACTION_DOWN:resetPoint();ij = getSelectPoint();if (ij != null) {isDraw = true;i = ij[0];j = ij[1];points[i][j].state = Point.STATE_PRESS;pressedPoints.add(points[i][j]);passList.add(i * points.length + j);}break;case MotionEvent.ACTION_MOVE:if (isDraw) {ij = getSelectPoint();if (ij != null) {i = ij[0];j = ij[1];if (!pressedPoints.contains(points[i][j])) {points[i][j].state = Point.STATE_PRESS;pressedPoints.add(points[i][j]);passList.add(i * points.length + j);}}}break;case MotionEvent.ACTION_UP:boolean valid = false;if (onDrawFinishedListener != null && isDraw) {valid = onDrawFinishedListener.onDrawFinished(passList);
// onDrawFinishedListener.onDrawFinished(passList);}
// if (passList.size() <= 3) {// valid = false;
// }else {// valid = true;
// }if (!valid) {for (Point p : pressedPoints) {p.state = Point.STATE_ERROR;}}isDraw = false;break;}invalidate();return true;}private int[] getSelectPoint() {Point pMouse = new Point(mouseX, mouseY);for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[0].length; j++) {if (points[i][j].distance(pMouse) < bitmapR) {int[] result = new int[2];result[0] = i;result[1] = j;return result;}}}return null;}public interface OnDrawFinishedListener {boolean onDrawFinished(List<Integer> passList);}private OnDrawFinishedListener onDrawFinishedListener;public void setOnDrawFinishedListener(OnDrawFinishedListener onDrawFinishedListener) {this.onDrawFinishedListener = onDrawFinishedListener;}
}
欢迎关注公众号。
Android 图案解锁相关推荐
- android 解锁图案代码,Android图案解锁code.docx
Android图案解锁code Main_Acitivity.javapackage com.example.lackpatternview;import android.os.Bundle;impo ...
- Flex【原创】模拟Android图案解锁
Flex 实现Android图案解锁功能 看见Andorid系统里面有图案解锁的功能,试想能用Flex的移动开发实现吗?答案是:完全可以! 环境:Flex 4.6(air3.2) 先看我的包结构: 第 ...
- 快给你的app上锁吧(android图案解锁)
序言:前两天因为项目的原因,去做了一下仿ios的数字解锁功能,然后写了那篇快给你的app上锁吧(android数字解锁),后来想到应用中常见的还有另外一种解锁就是绘制图案解锁,这两种解锁的布局看起来是 ...
- Android 图案解锁 9宫格密码解锁
序言 第一次写Android技术博客,不知道该如何下手. 背景 现在人们越来越重视自己的隐私,对于一些涉及用户隐私的应用,用户可能会希望在应用启动时必须先输入密码.传统的数字式密码记忆繁琐.容易破 ...
- android图案解锁功能的实现
我们经常会在app中看到图案解锁的功能,所以寻思做一个,在某客视频上看到了教程,自己跟着做了一遍,记录一下,顺便理清一下思路. 思路讲解: 首先自定义一个图案的view,其中实现onDraw方法,以及 ...
- android 图案解锁忘记了,安卓手机忘记图形解锁、锁屏密码的解决方法
Android 手机的图形解锁倒是真的好用了,主要是方便新颖,并且便于记忆,自从有了图形解锁,很多人都不再使用密码屏幕锁了,图形解锁倒是好玩,但是经常换来换去的话就会造成一时间想不起哪个图形解锁图案才 ...
- android图案解锁忘了怎么解,安卓手机解锁图案忘了怎么办?手机解锁密码忘了的解决办法...
现在的智能手机解锁方法有很多,有的朋友喜欢几天换一个密码.但是有的人就会把自己设的手机解锁图案密码忘记了,今天小编就带着大家一起解决这个问题,赶紧和小编一起看看吧 一共有三种办法: 1.双清(恢复出厂 ...
- android图案解锁忘了怎么解,手机图案解锁忘了怎么办 三种方法轻松解决【图文】...
随着智能机的普及,手机上锁方法也有了新的方式,除了以前传统的密码锁之外,手机还添加了极富趣味的图案锁.九宫格形式的图案锁屏,看上去不仅新颖,而且锁屏更加方面,这种锁屏很快就受到不少用户的喜爱!可是在使 ...
- android 图案解锁密码,关于Android手机图案解锁总密码数,个人写的一个递归版求解...
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 没有注释,测试运行一下就行了,大部分人还是能看懂的. import java.util.Vector; public class TestLock { p ...
最新文章
- Spring Cloud Kubernetes 指南
- python一个月能挣多少钱-零基础学python,我可以让你一个月上手做项目!
- 提升win双屏体验_海信双屏A6L评测,在自由阅读中植入护眼水墨屏
- Flink Forward Global 2021 议题征集ing!
- mysql数据库-mysql数据定义语言DDL (Data Definition Language)归类(六)
- 人生历练必备的十个心态(图)
- [org.hibernate.util.JDBCExceptionReporter] - Cannot load JDBC driver class 'net.
- java页面渲染_史上最详细的页面渲染机制
- 常见的7种深度学习框架对比
- Android Ptrace Inject
- 小学生机器人挑战赛_厉害了我的小学生!德阳中小学生机器人大赛
- 一位硕士毕业生三个月求职经历与经验的结晶
- S7-300系列PLC如何通过GSD文件实现PROFIBUS DP主从通讯?
- Excel如何对多分隔符号数据进行分列
- python关键词排名批量查排名_Python 批量获取Baidu关键词的排名并入库
- ubuntu20.04 常用开发工具整理
- 第1章思维导图图片版
- 如何实现小程序的无限推送
- android开机默认打开指定程序,android 开机默认进入指定Launcher
- Linux根目录下各目录的作用