当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义控件实现九宫格解锁功能

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

最终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>

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网