溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android自定義控件實(shí)現(xiàn)九宮格解鎖功能

發(fā)布時(shí)間:2020-09-14 12:16:55 來源:腳本之家 閱讀:157 作者:一生中所愛 欄目:移動開發(fā)

最終Android九宮格解鎖效果如下

Android自定義控件實(shí)現(xiàn)九宮格解鎖功能

1.進(jìn)行定義實(shí)體point點(diǎn)

public class Point {
 private float x;
 private float y;
 //正常模式
 public static final int NORMAL_MODE = 1;
 //按下模式
 public static final int PRESSED_MODE = 2;
 //錯(cuò)誤模式
 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";

 // 錯(cuò)誤格子的圖片
 private Bitmap errorBitmap;
 // 正常格子的圖片
 private Bitmap normalBitmap;
 // 手指按下時(shí)格子的圖片
 private Bitmap pressedBitmap;
 // 錯(cuò)誤時(shí)連線的圖片
 private Bitmap lineErrorBitmap;
 // 手指按住時(shí)連線的圖片
 private Bitmap linePressedBitmap;
 // 偏移量,使九宮格在屏幕中央
 private int offset;
 // 九宮格的九個(gè)格子是否已經(jīng)初始化
 private boolean init;
 // 格子的半徑
 private int radius;
 // 密碼
 private String password = "123456";
 // 九個(gè)格子
 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;
 // 是否可以觸摸,當(dāng)用戶抬起手指,劃出九宮格的密碼不正確時(shí)為不可觸摸
 private boolean isTouch = true;
 // 用來存儲記錄被按下的點(diǎn)
 private List<Point> pressedPoint = new ArrayList<>();
 // 屏幕解鎖監(jiān)聽器
 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++) {
   // 得到當(dāng)前格子
   Point point = pressedPoint.get(i);
   // 得到下一個(gè)格子
   Point nextPoint = pressedPoint.get(i + 1);
   // 旋轉(zhuǎn)畫布
   canvas.rotate(RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());

   matrix.reset();
   // 根據(jù)距離設(shè)置拉伸的長度
   matrix.setScale(getDistance(point, nextPoint) / linePressedBitmap.getWidth(), 1f);
   // 進(jìn)行平移
   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);
   }
   // 把畫布旋轉(zhuǎn)回來
   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());
  }
 }

 // 根據(jù)point和坐標(biāo)點(diǎn)計(jì)算出之間的距離
 private float getDistance(Point point, float moveX, float moveY) {
  Point b = new Point(moveX,moveY,null);
  return getDistance(point,b);
 }

 // 根據(jù)兩個(gè)point計(jì)算出之間的距離
 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);
    }
   }
  }
 }

 //初始化九宮格的點(diǎn)
 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:
     // 判斷用戶觸摸的點(diǎn)是否在九宮格的任意一個(gè)格子之內(nèi)
     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);
 }
}

用到的圖片資源

Android自定義控件實(shí)現(xiàn)九宮格解鎖功能Android自定義控件實(shí)現(xiàn)九宮格解鎖功能Android自定義控件實(shí)現(xiàn)九宮格解鎖功能

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 = "密碼錯(cuò)誤";
    }
    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>

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI