快给你的app上锁吧(android图案解锁)
生活随笔
收集整理的這篇文章主要介紹了
快给你的app上锁吧(android图案解锁)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
序言:前兩天因為項目的原因,去做了一下仿ios的數(shù)字解鎖功能,然后寫了那篇快給你的app上鎖吧(android數(shù)字解鎖),后來想到應用中常見的還有另外一種解鎖就是繪制圖案解鎖,這兩種解鎖的布局看起來是很相似的,而且產(chǎn)生的結(jié)果也很相似,但是用戶的操作不一樣,下面我就給大家來說明一下
話不多說,先上圖:
正常狀態(tài)
按下狀態(tài)
抬起錯誤狀態(tài)
抬起正確狀態(tài)
思路 這里又是一個九宮格布局,布局可以參考上一篇快給你的app上鎖吧(android數(shù)字解鎖),只不過這里的九宮格上我們畫的是圖片(bitmap)。onDraw方法中我們需要畫兩個東西,一個是點,另一個是線,畫點我們就不多說了,根據(jù)坐標,將圓形圖片畫上去即可;
下面我們來看畫線:
1、首先先要獲得按下點的集合:
我們可以用集合來保存touch事件中按下的時候是九宮格中的點 復制代碼2、然后每兩個點連成一條線
首先需要判斷第一個點的狀態(tài)是否是正常的(這個是點的屬性,可以自定義),正常的話兩點之間就連正確的線,錯誤的話兩點之間就連錯誤的線 復制代碼布局畫好之后我們還需要判斷手勢,即onTouch事件,按下,移動,抬起。
1、按下:
(1). 清空之前的操作,新一輪的繪制圖案開始 (2). 檢查當前按下的點與九宮格中的點是否吻合,如果吻合,將判斷第一次是否選中九宮格中的點這個標識位置為true 復制代碼2、移動:
(1). 判斷第一次按下是否選中九宮格中的點 (2). 如果第一次選中九宮格中的點,將手指在移動且手指按下的點不是九宮格中的點這個標識位置為true 復制代碼3、抬起:
(1). 將所有的標識位都還原成初始化 復制代碼繪制結(jié)束:
1、先判斷繪制成不成立
2、然后根據(jù)繪制的結(jié)果向界面發(fā)送回調(diào)
至此,相關分析就結(jié)束了,詳細的釋義我會在代碼中給出:
public class GraphicLockView extends View {private Point[][] points = new Point[3][3]; //創(chuàng)建一個3行3列的點數(shù)組private boolean isInit; //判斷有沒有初始化private boolean isSelect; //判斷手指第一次按下屏幕有沒有選中點private boolean isFinishMove; //表示一次完整的圖案繪制是否結(jié)束private boolean isMoveButNotPoint; //表示手指在移動,但是并不是九宮格中的點private float width, height; //屏幕寬高private static final int MIN_POINT = 4; //最小能構(gòu)成密碼的點數(shù)private float offsetsX, offsetsY; //偏移量(在這里偏移量等于大邊減去小邊再除以2)private float bitmapR; //圖片資源的半徑private float moveX, moveY; //手勢移動的x,y坐標private Bitmap bpPointNormal, bpPointPressed, bpPointError; //點的三種圖片private Bitmap bpLinePressed, bpLineError; //線的三種圖片private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);private List<Point> selectPointList = new ArrayList<>(); //儲存按下的點的集合private Matrix matrix = new Matrix(); //矩陣,用來處理線的縮放private OnGraphicLockListener onGraphicLockListener; //對外的監(jiān)聽器public GraphicLockView(Context context) {super(context);}public GraphicLockView(Context context, AttributeSet attrs) {super(context, attrs);}public GraphicLockView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public void setOnGraphicLockListener(OnGraphicLockListener onGraphicLockListener) {this.onGraphicLockListener = onGraphicLockListener;}@Overrideprotected void onDraw(Canvas canvas) {//繪制之前要先初始化一下點,所以要先判斷有沒有初始化過if (!isInit) {//初始化點initPoints();}//繪制——將點繪制到畫布上pointToCanvas(canvas);if (selectPointList.size() > 0) {Point startPoint = selectPointList.get(0);//繪制九宮格坐標里的點for (int i = 0; i < selectPointList.size(); i++) {Point endPoint = selectPointList.get(i);lineToCanvas(canvas, startPoint, endPoint);startPoint = endPoint;}//繪制九宮格坐標以外的點if (isMoveButNotPoint) {lineToCanvas(canvas, startPoint, new Point(moveX, moveY));}}}/*** 初始化點*/private void initPoints() {//1、先拿到畫布的寬高(屏幕的寬高)width = getWidth();height = getHeight();/*================================================================================*///2、判斷橫豎屏并且計算偏移量if (width > height) { //橫屏//橫屏時只有x坐標有偏移量offsetsX = (width - height) / 2;/*** 將手機屏幕可以看作是一個正方形(因為九宮格是正方形,在這里比較好計算),以最小邊為基準*/width = height;} else { //豎屏//豎屏時只有y坐標有偏移量offsetsY = (height - width) / 2;height = width;}/*================================================================================*///3、圖片資源(圖片資源自己加上)bpPointNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);bpPointPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);bpPointError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);bpLinePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);bpLineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);/*================================================================================*///4、點的坐標//第一排points[0][0] = new Point(offsetsX + width / 4, offsetsY + height / 4);points[0][1] = new Point(offsetsX + width / 2, offsetsY + height / 4);points[0][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 4);//第二排points[1][0] = new Point(offsetsX + width / 4, offsetsY + height / 2);points[1][1] = new Point(offsetsX + width / 2, offsetsY + height / 2);points[1][2] = new Point(offsetsX + width - width / 4, offsetsY + height / 2);//第三排points[2][0] = new Point(offsetsX + width / 4, offsetsY + height - height / 4);points[2][1] = new Point(offsetsX + width / 2, offsetsY + height - height / 4);points[2][2] = new Point(offsetsX + width - width / 4, offsetsY + height - height / 4);/*================================================================================*///5、計算圖片資源的半徑bitmapR = bpPointNormal.getWidth() / 2;/*================================================================================*///6、設置密碼按鍵,初始化每個點,設置為1——9int index = 1;for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {points[i][j].index = index;index++;}}/*================================================================================*///初始化完成isInit = true;}@Overridepublic boolean onTouchEvent(MotionEvent event) {moveX = event.getX();moveY = event.getY();isFinishMove = false;isMoveButNotPoint = false;Point point = null;switch (event.getAction()) {case MotionEvent.ACTION_DOWN://每次手指按下的時候都表示重新繪制圖案resetPoint();//1、檢查當前按下的點與九宮格中的九個點是否吻合point = checkSelectPoint();if (point != null) {isSelect = true;}break;case MotionEvent.ACTION_MOVE:if (isSelect) {point = checkSelectPoint();if (point == null) {isMoveButNotPoint = true;}}break;case MotionEvent.ACTION_UP:isFinishMove = true;isSelect = false;break;}//選中重復檢查if (!isFinishMove && isSelect && point != null) {if (checkCrossPoint(point)) { //交叉點isMoveButNotPoint = true;} else { //非交叉點(新的點)point.status = Point.STATE_PRESSED;selectPointList.add(point);}}//繪制結(jié)束if (isFinishMove) {//繪制不成立if (selectPointList.size() == 1) {resetPoint();//繪制錯誤,點不夠} else if (selectPointList.size() < MIN_POINT && selectPointList.size() > 0) {if (null != onGraphicLockListener) {onGraphicLockListener.setPwdFailure();}errorPoint();//繪制成功} else {if (null != onGraphicLockListener) {String strPassword = "";for (Point pwdPoint : selectPointList) {strPassword += pwdPoint.index;}if (!TextUtils.isEmpty(strPassword)) {onGraphicLockListener.setPwdSuccess(strPassword);}correctPoint();}}}//刷新view,會調(diào)用onDraw方法postInvalidate();return true;}/*** 檢查交叉點** @param point 點* @return 是否交叉*/private boolean checkCrossPoint(Point point) {if (selectPointList.contains(point)) {return true;}return false;}/*** 設置繪制不成立*/public void resetPoint() {//將點的狀態(tài)還原for (Point point : selectPointList) {point.status = Point.STATE_NORMAL;}selectPointList.clear();}/*** 設置繪制錯誤,將點的狀態(tài)還原*/public void errorPoint() {for (Point point : selectPointList) {point.status = Point.STATE_ERROR;}new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}handler.sendEmptyMessage(0);}}).start();}/*** 設置繪制成功,將點的狀態(tài)還原*/private void correctPoint() {new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}handler.sendEmptyMessage(0);}}).start();}private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {for (Point point : selectPointList) {point.status = Point.STATE_NORMAL;}selectPointList.clear();postInvalidate();}};private Point checkSelectPoint() {for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {Point point = points[i][j];if (AppUtil.isCoincide(point.x, point.y, bitmapR, moveX, moveY)) {return point;}}}return null;}/*** 將點繪制到畫布上** @param canvas 畫布*/private void pointToCanvas(Canvas canvas) {//遍歷點的集合for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {Point point = points[i][j];if (points[i][j].status == Point.STATE_PRESSED) {canvas.drawBitmap(bpPointPressed, point.x - bitmapR, point.y - bitmapR, mPaint);} else if (points[i][j].status == Point.STATE_ERROR) {canvas.drawBitmap(bpPointError, point.x - bitmapR, point.y - bitmapR, mPaint);} else {canvas.drawBitmap(bpPointNormal, point.x - bitmapR, point.y - bitmapR, mPaint);}}}}/*** 將線繪制到畫布上** @param canvas 畫布* @param startPoint 開始的點* @param endPoint 結(jié)束的點*/private void lineToCanvas(Canvas canvas, Point startPoint, Point endPoint) {float lineLength = (float) AppUtil.twoPointDistance(startPoint, endPoint);float degree = AppUtil.getDegrees(startPoint, endPoint);canvas.rotate(degree, startPoint.x, startPoint.y); //旋轉(zhuǎn)if (startPoint.status == Point.STATE_PRESSED) { //按下的狀態(tài)//設置線的縮放比例,在這里線是往一個方向縮放的,即x軸,我們只需要設置x軸的縮放比例即可,y軸默認為1matrix.setScale(lineLength / bpLinePressed.getWidth(), 1);matrix.postTranslate(startPoint.x - bpLinePressed.getWidth() / 2, startPoint.y - bpLinePressed.getHeight() / 2);canvas.drawBitmap(bpLinePressed, matrix, mPaint);} else { //錯誤的狀態(tài)matrix.setScale(lineLength / bpLineError.getWidth(), 1);matrix.postTranslate(startPoint.x - bpLineError.getWidth() / 2, startPoint.y - bpLineError.getHeight() / 2);canvas.drawBitmap(bpLineError, matrix, mPaint);}canvas.rotate(-degree, startPoint.x, startPoint.y); //把旋轉(zhuǎn)的角度轉(zhuǎn)回來}/*** 圖案監(jiān)聽器*/public interface OnGraphicLockListener {void setPwdSuccess(String password);void setPwdFailure();} } 復制代碼來看一波gif動圖:
Github下載地址:傳送門
總結(jié)
以上是生活随笔為你收集整理的快给你的app上锁吧(android图案解锁)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 联想云:借助云计算助力中国企业数字化转型
- 下一篇: RunLoop的学习