欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-04 11:24:28
最终android九宫格解锁效果如下 1.进行定义实体point点 public class point { private float x;...

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

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);
 }
}

用到的图片资源

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

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>

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