package com.weiqiang.lockpoint; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.text.TextUtils; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @SuppressLint({ "ClickableViewAccessibility", "DrawAllocation" }) public class LockPatternView extends View { //监听器 private OnPatterChangeListner onPatterChangeListner; private static int POINT_SIZE = 5; // 画笔 private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // 定义九个点 public Point[][] points = new Point[4][4]; // 矩阵 private Matrix matrix = new Matrix(); private boolean isInit, isSelect, isFinish, movingNoPoint; private float width, height, offsetX, offsetY, bitmapR, movingX, movingY; private Bitmap pointsNomal, pointsPressed, pointsError, linePressed, lineError; private List<Point> pointList = new ArrayList<Point>(); public LockPatternView(Context context) { super(context); } public LockPatternView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub } public LockPatternView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } /** * 初始化九个点 */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); if (!isInit) { initPoints(); } point2Canvas(canvas); if (pointList.size() > 0) { // 绘制九宫格里面的点 Point a = pointList.get(0); for (int i = 0; i < pointList.size(); i++) { Point b = pointList.get(i); line2Canvas(canvas, a, b); a = b; } // 绘制鼠标坐标点 if (movingNoPoint) { line2Canvas(canvas, a, new Point(movingX, movingY)); } } } /** * 绘制划线 * * @param canvas * 画布 * @param a * 第一个点 * @param b * 第二个点 */ private void line2Canvas(Canvas canvas, Point a, Point b) { // 线的长度 float lineLength = (float) Point.distance(a, b); float degrees = getDegree(a, b); canvas.rotate(degrees, a.x, a.y); if (a.state == Point.STATE_PRESSED) { matrix.setScale(lineLength / linePressed.getWidth(), 1); // 矩阵处理线的平移动,从第一个点进行平移 matrix.postTranslate(a.x - linePressed.getWidth() / 2, a.y- linePressed.getHeight() / 2); canvas.drawBitmap(linePressed, matrix, paint); } else { matrix.setScale(lineLength / lineError.getWidth(), 1); // 矩阵处理线的平移动,从第一个点进行平移 matrix.postTranslate(a.x - lineError.getWidth() / 2, a.y- lineError.getHeight() / 2); canvas.drawBitmap(lineError, matrix, paint); } canvas.rotate(-degrees, a.x, a.y); } /** * 将点绘制到画布上 * * @param canvas */ private void point2Canvas(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 (point.state == Point.STATE_PRESSED) { canvas.drawBitmap(pointsPressed, point.x - bitmapR, point.y - bitmapR, paint); } else if (point.state == Point.STATE_ERROR) { canvas.drawBitmap(pointsError, point.x - bitmapR, point.y - bitmapR, paint); } else { canvas.drawBitmap(pointsNomal, point.x - bitmapR, point.y - bitmapR, paint); } } } } /** * 初始化点 */ private void initPoints() { // 1.获取手机的宽高 width = getWidth(); height = getHeight(); // 2.计算 x,y偏移量 // 判断手机横屏或者竖屏 // 横屏 if (width > height) { offsetX = (width - height)/5; System.out.println(offsetX); width = height; // 竖屏 } else { offsetY = (height - width)/5; System.out.println(offsetY); height = width; } // 3.获取图片资源 pointsNomal = BitmapFactory.decodeResource(getResources(),R.drawable.point_nomal); pointsPressed = BitmapFactory.decodeResource(getResources(),R.drawable.point_pressed); pointsError = BitmapFactory.decodeResource(getResources(),R.drawable.point_error); linePressed = BitmapFactory.decodeResource(getResources(),R.drawable.line_pressed); lineError = BitmapFactory.decodeResource(getResources(),R.drawable.line_error); // 4. 绘制点 // 第一行 points[0][0] = new Point(offsetX + width / 5, offsetY + width / 5); points[0][1] = new Point(offsetX + width*2/5, offsetY + width / 5); points[0][2] = new Point(offsetX + width*3/5, offsetY + width/ 5); points[0][3] = new Point(offsetX + width*4/5, offsetY + width/5); // 第二行 points[1][0] = new Point(offsetX + width / 5, offsetY + width *2/5); points[1][1] = new Point(offsetX + width*2/ 5, offsetY + width *2/ 5); points[1][2] = new Point(offsetX + width*3 / 5, offsetY + width*2/ 5); points[1][3] = new Point(offsetX + width*4/5, offsetY + width*2/5 ); // 第三行 points[2][0] = new Point(offsetX + width / 5, offsetY + width*3/ 5); points[2][1] = new Point(offsetX + width *2/5, offsetY + width*3/ 5); points[2][2] = new Point(offsetX + width*3 /5, offsetY + width*3/5); points[2][3] = new Point(offsetX + width*4/5, offsetY + width*3/5 ); //第四行 points[3][0] = new Point(offsetX + width / 5, offsetY + width*4/5); points[3][1] = new Point(offsetX + width *2/5, offsetY + width*4/5); points[3][2] = new Point(offsetX + width*3 /5, offsetY + width*4/5); points[3][3] = new Point(offsetX + width*4/5, offsetY + width*4/5); // 5.处理图片资源的半径 bitmapR = pointsNomal.getHeight() / 2; //6.设置密码 int index = 1; for(Point [] points:this.points){ for(Point point:points){ point.index = index; index++; } } // 7.初始化完成 isInit = true; } @Override public boolean onTouchEvent(MotionEvent event) { movingNoPoint = false; isFinish = false; movingX = event.getX(); movingY = event.getY(); Point point = null; switch (event.getAction()) { // 按下 case MotionEvent.ACTION_DOWN: //重新绘制 if (onPatterChangeListner!=null) { onPatterChangeListner.onPatterStart(true); } resets(); point = checkSelectPoint(); if (point != null) { isSelect = true; } break; // 移动 case MotionEvent.ACTION_MOVE: if (isSelect) { point = checkSelectPoint(); if (point == null) { movingNoPoint = true; } } break; // 抬起 case MotionEvent.ACTION_UP: isFinish = true; isSelect = false; break; } // 选中重复检查 if (!isFinish && isSelect && point != null) { // 交叉点 if (crossPoint(point)) { movingNoPoint = true; // 新点 } else { point.state = Point.STATE_PRESSED; pointList.add(point); } } // 绘制结束 if (isFinish) { // 绘制不成立 if (pointList.size() == 1) { // 清除集合 resets(); // 绘制错误 } else if (pointList.size() < POINT_SIZE && pointList.size() > 0) { errorPoint(); if(onPatterChangeListner!=null){ onPatterChangeListner.onPatterChange(null); } //绘制成功 }else { if(onPatterChangeListner!=null){ String passString =""; for (int i = 0; i < pointList.size(); i++) { passString+=pointList.get(i).index; } if (!TextUtils.isEmpty(passString)) { onPatterChangeListner.onPatterChange(passString); } } } } // 刷新View postInvalidate(); return true; } /** * 交叉点的检查 * * @param point点 * @return 是否交叉 */ private boolean crossPoint(Point point) { if (pointList.contains(point)) { return true; } else { return false; } } /** * 设置绘制不成立 */ public void resets() { for (int i = 0; i < pointList.size(); i++) { Point point = pointList.get(i); point.state = Point.STATE_NOMAL; } pointList.clear(); } /** * 设置绘制错误 */ public void errorPoint() { for (Point point : pointList) { point.state = Point.STATE_ERROR; } } /** * 检查鼠标的点是否和九宫格中的点重合 */ 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 (Point.with(point.x, point.y, bitmapR, movingX, movingY)) { return point; } } } return null; } /** * 自定义的点 */ public static class Point { public static int STATE_NOMAL = 0; public static int STATE_PRESSED = 1; public static int STATE_ERROR = 2; public float x, y; public int index = 0, state = 0; public Point() { // TODO Auto-generated constructor stub } public Point(float x, float y) { this.x = x; this.y = y; } /** * 两点的距离 * * @param a * 点a * @param b * 点b * @return 距离 */ public static double distance(Point a, Point b) { // X轴差的平方+Y轴差的平方,对和开方 return Math.sqrt(Math.abs(a.x - b.x) * Math.abs(a.x - b.x) + Math.abs(a.y - b.y) * Math.abs(a.y - b.y)); } /** * 是否重合 * * @param pointX * 参考点的X * @param pointY * 参考点的Y * @param r * 圆的半径 * @param movingX * 移动点的X * @param movingY * 移动点的Y * @return 是否重合 */ public static boolean with(float pointX, float pointY, float r, float movingX, float movingY) { // 开方 return Math.sqrt((pointX - movingX) * (pointX - movingX) + (pointY - movingY) * (pointY - movingY)) < r; } } /** * 获取角度 * * @param a * 第一个点 * @param b * 第二个点 * @return 角度 */ public float getDegree(Point a, Point b) { float ax = a.x; float ay = a.y; float bx = b.x; float by = b.y; float degree = 0; if (ax == bx) {// Y轴相等 90度或者270度 if (by > ay) { degree = 90; } else if (by < ay) { degree = 270; } } else if (by == ay) {// X轴相等 0度或者180度 if (bx > ax) { degree = 0; } else if (bx < ax) { degree = 180; } } else if (bx > ax) {//在Y轴右边270~90 if(by>ay){//在Y轴下面0~90 degree = 0; degree = degree+switchDegree(Math.abs(by-ay),Math.abs(bx-ax)); }else if(by<ay){//在Y轴的上边 270~0 degree = 360; degree = degree-switchDegree(Math.abs(by-ay),Math.abs(bx-ax)); } } else if (bx < ax) {//在Y轴左边 90~270 if(by>ay){//在Y轴下面180~270 degree = 90; degree = degree+switchDegree(Math.abs(bx-ax),Math.abs(by-ay)); }else if(by<ay){//在Y轴的上边90~180 degree = 270; degree = degree-switchDegree(Math.abs(bx-ax),Math.abs(by-ay)); } } return degree; } private float switchDegree(float x,float y){ //弧度转化为角度 return (float) Math.toDegrees(Math.atan2(x, y)); } /** * 图案监听器 * @author Administrator * */ public static interface OnPatterChangeListner{ /** * 图案改变 * @param passString 图案的密码 */ void onPatterChange(String passString); /** * 是否开始绘制图案 * @param isStart是否重新绘制 */ void onPatterStart(boolean isStart); } /** * 设置图案监听器 * @param onPatterChangeListner */ public void setPatterChangeListner(OnPatterChangeListner onPatterChangeListner){ if(onPatterChangeListner!=null){ this.onPatterChangeListner = onPatterChangeListner; } } }
最近下载更多
zzzxxcc LV6
2020年6月17日
开心的一只鱼 LV8
2020年6月16日
花花滑滑画画瓜瓜 LV9
2020年1月9日
871978898 LV1
2019年12月25日
zb1095876169 LV2
2019年12月24日
藤井旋风 LV4
2019年12月14日
lyt1234567890 LV5
2019年12月4日
1198903926 LV9
2019年11月25日
阿凝是个小可爱 LV14
2019年6月29日
那一丝涟漪 LV8
2019年5月26日