首页 > 系统 > Android > 正文

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

2019-12-12 02:48:57
字体:
来源:转载
供稿:网友

最终Android九宫格解锁效果如下

1.进行定义实体point点

public class Point { private float x; private float y; //正常模式 public static final int NORMAL_MODE = 1; //按下模式 public static final int PRESSED_MODE = 2; //错误模式 public static final int ERROR_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 String TAG = "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="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/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.ScreenLockView  android:id="@+id/slv"  android:layout_width="match_parent"  android:layout_height="match_parent" /></RelativeLayout>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表