1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Android自定义控件实现九宫格解锁

Android自定义控件实现九宫格解锁

时间:2023-10-15 13:18:18

相关推荐

Android自定义控件实现九宫格解锁

最终效果如下

1.进行定义实体point点

public class Point {private float x; private float y; //正常模式 public static final intNORMAL_MODE= 1; //按下模式 public static final intPRESSED_MODE= 2; //错误模式 public static final intERROR_MODE= 3; private int state =NORMAL_MODE; private String mark; public Point(float x, float y, String mark) {this.x = x; this.y = y; this.mark = mark; }public float getX() {return x; }public void setX(float x) {this.x = x; }public float getY() {return y; }public void setY(float y) {this.y = y; }public int getState() {return state; }public void setState(int state) {this.state = state; }public String getMark() {return mark; }public void setMark(String mark) {this.mark = mark; }}

2.自定义ScreenLockView

public class ScreenLockView extends View {private static final StringTAG= "ScreenLockView"; // 错误格子的图片 private Bitmap errorBitmap; // 正常格子的图片 private Bitmap normalBitmap; // 手指按下时格子的图片 private Bitmap pressedBitmap; // 错误时连线的图片 private Bitmap lineErrorBitmap; // 手指按住时连线的图片 private Bitmap linePressedBitmap; // 偏移量,使九宫格在屏幕中央 private int offset; // 九宫格的九个格子是否已经初始化 private boolean init; // 格子的半径 private int radius; // 密码 private String password = "123456"; // 九个格子 private Point[][] points = new Point[3][3]; private int width; private int height; private Matrix matrix = new Matrix(); private float moveX = -1; private float moveY = -1; // 是否手指在移动 private boolean isMove; // 是否可以触摸,当用户抬起手指,划出九宫格的密码不正确时为不可触摸 private boolean isTouch = true; // 用来存储记录被按下的点 private List<Point> pressedPoint = new ArrayList<>(); // 屏幕解锁监听器 private OnScreenLockListener listener; public ScreenLockView(Context context) {super(context); init(); }public ScreenLockView(Context context, AttributeSet attrs) {super(context, attrs); init(); }public ScreenLockView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr); init(); }private void init() {errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_error); normalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_normal); pressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_pressed); lineErrorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_error); linePressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed); radius = normalBitmap.getWidth() / 2; }@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (widthSize > heightSize) {offset = (widthSize - heightSize) / 2; } else {offset = (heightSize - widthSize) / 2; }setMeasuredDimension(widthSize, heightSize); }@Override protected void onDraw(Canvas canvas) {super.onDraw(canvas); if (!init) {width = getWidth(); height = getHeight(); initPoint(); init = true; }drawPoint(canvas); if (moveX != -1 && moveY != -1) {drawLine(canvas); }}// 画直线 private void drawLine(Canvas canvas) {// 将pressedPoint中的所有格子依次遍历,互相连线 for (int i = 0; i < pressedPoint.size() - 1; i++) {// 得到当前格子 Point point = pressedPoint.get(i); // 得到下一个格子 Point nextPoint = pressedPoint.get(i + 1); // 旋转画布 canvas.rotate(RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY()); matrix.reset(); // 根据距离设置拉伸的长度 matrix.setScale(getDistance(point, nextPoint) / linePressedBitmap.getWidth(), 1f); // 进行平移 matrix.postTranslate(point.getX(), point.getY() - linePressedBitmap.getWidth() / 2); if (point.getState() == Point.PRESSED_MODE) {canvas.drawBitmap(linePressedBitmap, matrix, null); } else {canvas.drawBitmap(lineErrorBitmap, matrix, null); }// 把画布旋转回来 canvas.rotate(-RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY()); }// 如果是手指在移动的情况 if (isMove) {Point lastPoint = pressedPoint.get(pressedPoint.size() - 1); canvas.rotate(RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY()); matrix.reset(); Log.i(TAG, "the distance : " + getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth()); matrix.setScale(getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth(), 1f); matrix.postTranslate(lastPoint.getX(), lastPoint.getY() - linePressedBitmap.getWidth() / 2); canvas.drawBitmap(linePressedBitmap, matrix, null); canvas.rotate(-RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY()); }}// 根据point和坐标点计算出之间的距离 private float getDistance(Point point, float moveX, float moveY) {Point b = new Point(moveX,moveY,null); return getDistance(point,b); }// 根据两个point计算出之间的距离 private float getDistance(Point point, Point nextPoint) {return (float) Math.sqrt(Math.pow(nextPoint.getX() - point.getX(), 2f) + Math.pow(nextPoint.getY() - point.getY(), 2f)); }private void drawPoint(Canvas canvas) {for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {int state = points[i][j].getState();if (state == Point.NORMAL_MODE) {canvas.drawBitmap(normalBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);} else if (state == Point.PRESSED_MODE) {canvas.drawBitmap(pressedBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);} else {canvas.drawBitmap(errorBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);}}}}//初始化九宫格的点 private void initPoint() {points[0][0] = new Point(width / 4, offset + width / 4, "0"); points[0][1] = new Point(width / 2, offset + width / 4, "1"); points[0][2] = new Point(width * 3 / 4, offset + width / 4, "2"); points[1][0] = new Point(width / 4, offset + width / 2, "3"); points[1][1] = new Point(width / 2, offset + width / 2, "4"); points[1][2] = new Point(width * 3 / 4, offset + width / 2, "5"); points[2][0] = new Point(width / 4, offset + width * 3 / 4, "6"); points[2][1] = new Point(width / 2, offset + width * 3 / 4, "7"); points[2][2] = new Point(width * 3 / 4, offset + width * 3 / 4, "8"); }@Override public boolean onTouchEvent(MotionEvent event) {if (isTouch) {float x = event.getX(); float y = event.getY(); Point point; switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 判断用户触摸的点是否在九宫格的任意一个格子之内point = isPoint(x, y);if (point != null) {point.setState(Point.PRESSED_MODE); // 切换为按下模式 pressedPoint.add(point);}break;case MotionEvent.ACTION_MOVE:if (pressedPoint.size() > 0) {point = isPoint(x, y); if (point != null) {if (!crossPoint(point)) {point.setState(Point.PRESSED_MODE); pressedPoint.add(point); }}moveX = x; moveY = y; isMove = true;}break;case MotionEvent.ACTION_UP:isMove = false;String tempPwd = "";for (Point p : pressedPoint) {tempPwd += p.getMark();}if (listener != null) {listener.getStringPassword(tempPwd);}if (tempPwd.equals(password)) {if (listener != null) {listener.isPassword(true); this.postDelayed(runnable, 1000); }} else {for (Point p : pressedPoint) {p.setState(Point.ERROR_MODE); }isTouch = false; this.postDelayed(runnable, 1000); if (listener != null) {listener.isPassword(false); }}break; }invalidate(); }return true; }private boolean crossPoint(Point point) {if (pressedPoint.contains(point)) {return true; }return false; }public interface OnScreenLockListener {public void getStringPassword(String password); public void isPassword(boolean flag); }public void setOnScreenLockListener(OnScreenLockListener listener) {this.listener = listener; }private Point isPoint(float x, float y) {Point point; for(int i = 0; i<points.length;i++){for (int j = 0; j < points[i].length; j++) {point = points[i][j];if (isContain(point, x, y)) {return point;}}}return null; }private boolean isContain(Point point, float x, float y) {return Math.sqrt(Math.pow(x - point.getX(), 2f) + Math.pow(y - point.getY(), 2f)) <= radius; }private Runnable runnable = new Runnable() {@Override public void run() {isTouch = true; reset(); invalidate(); }}; // 重置格子 private void reset(){for (int i = 0; i < points.length; i++) {for (int j = 0; j < points[i].length; j++) {points[i][j].setState(Point.NORMAL_MODE); }}pressedPoint.clear(); }}

3.RotateDegress类

public class RotateDegrees {public static float getDegrees(Point a, Point b){float degrees = 0 ; float aX = a.getX(); float aY = a.getY(); float bX = b.getX(); float bY = b.getY(); if(aX == bX){if(aY<bY){degrees = 90; }else{degrees = 270; }}else if(bY == aY){if(aX<bX){degrees = 0 ; }else{degrees = 180; }}else{if(aX>bX){if(aY>bY){degrees = 180 + (float)(Math.atan2(aY-bY,aX-bX)*180/Math.PI);}else{degrees = 180 - (float)(Math.atan2(bY -aY,aX - bX)*180/Math.PI);}}else{if(aY>bY){degrees = 360 -(float)(Math.atan2(aY - bY,bX-aX)*180/Math.PI);}else{degrees = (float)(Math.atan2(bY - aY,bX - aX)*180/Math.PI);}}}return degrees; }public static float getDegrees(Point a, float bX,float bY){Point b = new Point(bX,bY,null); return getDegrees(a,b); }}

用到的图片资源

4.MainActivity中使用

public class MainActivity extends AppCompatActivity {private ScreenLockView screenLockView; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); screenLockView = (ScreenLockView) findViewById(R.id.slv); screenLockView.setOnScreenLockListener(new ScreenLockView.OnScreenLockListener() {@Override public void getStringPassword(String password) {}@Override public void isPassword(boolean flag) {String content;if (flag) {content = "密码正确";} else {content = "密码错误";}Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show(); }}); }}

5.布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="/apk/res/android" xmlns:tools="/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.admin.ninegridunlock.MainActivity"> <com.example.admin.ninegridunlock.ScreenLockViewandroid:id="@+id/slv"android:layout_width="match_parent"android:layout_height="match_parent" /></RelativeLayout>

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。