Android九宫格锁屏

Android 九宫格锁屏(已更新,添加了用户操作记录密码,更加完善,更新的在下面)
此demo的重点就在于九宫点的绘制,与用户操作手势的监听交互

效果图

实现思路1(点的绘制)

  • 在绘制之前首先确定绘制九点整体的位置,这里将九点确定在居中
  • 要想将九点分别按顺序绘制在屏幕中,要知道屏幕的宽高
  • 因为九点为三行三列所以我们可以讲中间绘制九点的区域给一个正方形,将正方形在分为4 × 4的小正方形
  • 接下来根据屏幕的宽高确定手机此时的横竖屏状态分别设置不同的偏移量和space(space为4×4小方格之一的边长)的值
此图为绘制九点之前的思路(竖屏状态)
思路图

下面我们先新建一个类 SudokuLockViewextends (继承)View,实现继承的方法

重写onDraw方法,在onDraw方法中首先判断要绘制的九点的位置是否初始化,如果没有则实现九点初始化的方法
  private void initView() {

        /**
         * 屏幕宽高
         */
        int pHigth = metrics.heightPixels;
        int pWidth = metrics.widthPixels;

        /**
         * X,Y的偏移量
         */
        float offsetX;
        float offsetY;
        float space; //小方格边长

        /**
         * 判断横竖屏设置对应的值
         */
        if (pHigth > pWidth){
            offsetX = 0;
            offsetY = (pHigth - pWidth)/2;
            space = pWidth/4;
        }else {
            offsetX = (pWidth - pHigth)/2;
            offsetY = 0;
            space = pHigth/4;
        }

        //以下可以用双层for循环更简便
        /**one lines**/
        myPoint[0][0] = new MyPoint(offsetX+space,offsetY+space);
        myPoint[0][1] = new MyPoint(offsetX+space*2,offsetY+space);
        myPoint[0][2] = new MyPoint(offsetX+space*3,offsetY+space);

        /**two lines**/
        myPoint[1][0] = new MyPoint(offsetX+space,offsetY+space*2);
        myPoint[1][1] = new MyPoint(offsetX+space*2,offsetY+space*2);
        myPoint[1][2] = new MyPoint(offsetX+space*3,offsetY+space*2);

        /**three lines**/
        myPoint[2][0] = new MyPoint(offsetX+space,offsetY+space*3);
        myPoint[2][1] = new MyPoint(offsetX+space*2,offsetY+space*3); 
        myPoint[2][2] = new MyPoint(offsetX+space*3,offsetY+space*3);
  }
初始化点的位置之后就可以开始绘制点了(此处的九点可以通过Paint绘制圆形的图标,也可以直接定义一个图片资源,直接将图片资源绘制出来),此处用的第二种方法,同样在初始的方法中添加资源图标的初始
        /**添加点的图片资源**/
        nBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.onetests);
        sBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.twotests);
        eBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.threetests);
之后就可以直接绘制出
  private void drawPoint(Canvas canvas) {
        for (int i = 0;i<myPoint.length;i++){
              for (int j = 0;j<myPoint[i].length;j++){
                  
                  /**
                   * 当然,此处可以判断九点的不同的状态,在绘制(正常的、选中的,错误的)
                   *
                   * @bitR 为图片资源的半径,因为画笔所绘制的不会是从中心电绘制,而是从左上角开始绘制,在这里x,y各减去半径,就会以图标中心的位置开始绘制
                   */
                  canvas.drawBitmap(sBitmap,myPoint[i][j].x-bitR,myPoint[i][j].y-bitR,paint);
               }
        }
  }

好了,现在在XML文件中把我们自定义的这个View添加一下,运行看看,九点的效果就出来了
实现思路2(用户操作)

  • 在用户手势监听的方法onTouchEvent中分别有三种状态(Down·Move·Up
  • 首先在用户手指点下的时候,就要以x,y生成一个点,并且将点返回,判断点的位置是否为九点中任一点的位置,如果是添加选中的点,并改变点的状态
  • 当用户手指移动时,同上,先判断是否选择的是九点中任意点,如果是,在此处再次判断,次点是否已经包含在选中点的集合中,如果没有包含,改变点的状态并添加
  • 在用户手指抬起的时候,先判断所绘制的点的总数是否大于规定的最小数量,分别以点的不同状态显示所选最小数是否满足,最后在判断,当用户操作屏幕后,并且选中点的数量大于0,那么就关闭绘制状态
下面为当用户手指点下并且滑动的时候生成的点,并且返回为选中的九点的任一点,没选中的返回为null
  /**
   * 返回是否选择的是点
   */
  private int[] getSelectPoint() {
        
        //MyPoint自定义的点的类 ,用户手指按下时以x,y生成的点
        MyPoint begainSelectPoint = new MyPoint(moveX,moveY);
        for (int i = 0;i<myPoint.length;i++){
            for (int j = 0;j<myPoint[i].length;j++){
                 //判断距离将选择的点的位置否和一定条件时,为选中
                if (myPoint[i][j].distance(begainSelectPoint) < bitR){

                    //定义长度为2的数组,返回选中点的X,Y
                    int[] result = new int[2];
                    result[0] = i;
                    result[1] = j;
                    return result;
                }
            }
        }
        return null;//选中的不是九点的任一点时
  }
下面上一下onTouchEvent的方法(在此方法中在用户没操作的时候都要显示选中点的状态,所以要及时更新View,可以用this.postInvalidate();方法,及时更新)
  @Override
  public boolean onTouchEvent(MotionEvent event) {
      moveX = event.getX();
      moveY = event.getY();
      switch (event.getAction()){
          case MotionEvent.ACTION_DOWN:
              if (isDrawing){
                  getSelect = getSelectPoint();//用int[]的类型接收
                  if (getSelect != null){
                      x = getSelect[0];//x
                      y = getSelect[1];//y
                      myPoint[x][y].start = MyPoint.SELECT;//设置点的状态
                      allPoint.add(myPoint[x][y]);//添加点到选择点的集合
                  }
              }
              break;
          case MotionEvent.ACTION_MOVE:
              if (isDrawing){
                  getSelect = getSelectPoint();
                  if (getSelect != null){
                      x = getSelect[0];
                      y = getSelect[1];
                      if (!allPoint.contains(myPoint[x][y])){//判断是否已经包含此点
                          myPoint[x][y].start = MyPoint.SELECT;
                          allPoint.add(myPoint[x][y]);
                      }
                  }
              }
              break;
          case MotionEvent.ACTION_UP:
              if (isDrawing){
                  if (allPoint.size() <= 3 && allPoint.size()>0){
                      Toast.makeText(getContext(),"至少不少于四点",Toast.LENGTH_SHORT).show();
                      for (int i = 0;i<allPoint.size();i++){
                          allPoint.get(i).start = MyPoint.ERROR;
                      }
                  }
              }
              if (allPoint.size() > 0){
                  isDrawing = false;
              }
              break;
      }
      this.postInvalidate();//及时更新
      return true;
  }
onTouchEvent方法之后就可以绘制线了,线的绘制是以两点划线,并且,每次讲第二次选择的线赋值为初始点,下面给下选中九点的任一点,和没选中是线的绘制
  private void drawPointLines(Canvas canvas) {
      if (allPoint.size() > 0){
          MyPoint A = allPoint.get(0);
          for (int a = 1;a<allPoint.size();a++){
              MyPoint B = allPoint.get(a);
              drawLines(canvas,A,B);//此为选中九点时的划线的方法
              A = B;
          }
          if (isDrawing){
              drawLines(canvas,A,new MyPoint(moveX,moveY));//当处于绘制状态时,没有选中时,划线就是一手指移动而绘制
          }
      }
  }
绘制线的方法,判断选择的点的个数,绘制不同状态的线
  /**
   * 通过两点绘制线
   * @param canvas
   * @param a
   * @param b
   */
  private void drawLines(Canvas canvas, MyPoint a, MyPoint b) {
      if (a.start == MyPoint.ERROR){
          canvas.drawLine(a.x,a.y,b.x,b.y,epaint);
      }else {
          canvas.drawLine(a.x,a.y,b.x,b.y,paint);
      }
  }
用户操作密码记录
  • 上面我们在用户操作的方法onTouchEvent中用三种状态,我们只需在用户按下和移动的状态中添加判断的方法,判断用户选择的是当前的哪一个点,我们在给每一个点设置不同的标志值,当用户保存时,我们可以将用户的选择点的标志保存起来即可(下面上下代码)
    private void setPassWord(int x, int y) {
    if (myPoint[x][y] == myPoint[0][0]){
    list.add("1");
    }else if (myPoint[x][y] == myPoint[0][1]){
    list.add("2");
    }else if (myPoint[x][y] == myPoint[0][2]){
    list.add("3");
    }else if (myPoint[x][y] == myPoint[1][0]){
    list.add("4");
    }else if (myPoint[x][y] == myPoint[1][1]){
    list.add("5");
    }else if (myPoint[x][y] == myPoint[1][2]){
    list.add("6");
    }else if (myPoint[x][y] == myPoint[2][0]){
    list.add("7");
    }else if (myPoint[x][y] == myPoint[2][1]){
    list.add("8");
    }else if (myPoint[x][y] == myPoint[2][2]){
    list.add("9");
    }
    }

上面的代码我们可以生成一个方法,在用户按下和移动的操作中调用即可

好了,九宫锁到此结束,有更好思路的请告知,以上文章如有错误,请热情指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,660评论 0 33
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,204评论 0 17
  • 首页 资讯 文章 资源 小组 相亲 登录 注册 首页 最新文章 IT 职场 前端 后端 移动端 数据库 运维 其他...
    Helen_Cat阅读 3,781评论 1 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707