Android九宮格鎖屏

Android 九宮格鎖屏(已更新嘱蛋,添加了用戶操作記錄密碼修陡,更加完善邀桑,更新的在下面)
此demo的重點(diǎn)就在于九宮點(diǎn)的繪制,與用戶操作手勢(shì)的監(jiān)聽(tīng)交互

效果圖

實(shí)現(xiàn)思路1(點(diǎn)的繪制)

  • 在繪制之前首先確定繪制九點(diǎn)整體的位置工窍,這里將九點(diǎn)確定在居中
  • 要想將九點(diǎn)分別按順序繪制在屏幕中割卖,要知道屏幕的寬高
  • 因?yàn)榫劈c(diǎn)為三行三列所以我們可以講中間繪制九點(diǎn)的區(qū)域給一個(gè)正方形,將正方形在分為4 × 4的小正方形
  • 接下來(lái)根據(jù)屏幕的寬高確定手機(jī)此時(shí)的橫豎屏狀態(tài)分別設(shè)置不同的偏移量和space(space為4×4小方格之一的邊長(zhǎng))的值
此圖為繪制九點(diǎn)之前的思路(豎屏狀態(tài))
思路圖

下面我們先新建一個(gè)類 SudokuLockViewextends (繼承)View患雏,實(shí)現(xiàn)繼承的方法

重寫(xiě)onDraw方法鹏溯,在onDraw方法中首先判斷要繪制的九點(diǎn)的位置是否初始化,如果沒(méi)有則實(shí)現(xiàn)九點(diǎn)初始化的方法
  private void initView() {

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

        /**
         * X淹仑,Y的偏移量
         */
        float offsetX;
        float offsetY;
        float space; //小方格邊長(zhǎng)

        /**
         * 判斷橫豎屏設(shè)置對(duì)應(yīng)的值
         */
        if (pHigth > pWidth){
            offsetX = 0;
            offsetY = (pHigth - pWidth)/2;
            space = pWidth/4;
        }else {
            offsetX = (pWidth - pHigth)/2;
            offsetY = 0;
            space = pHigth/4;
        }

        //以下可以用雙層for循環(huán)更簡(jiǎn)便
        /**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);
  }
初始化點(diǎn)的位置之后就可以開(kāi)始繪制點(diǎn)了(此處的九點(diǎn)可以通過(guò)Paint繪制圓形的圖標(biāo)丙挽,也可以直接定義一個(gè)圖片資源,直接將圖片資源繪制出來(lái))匀借,此處用的第二種方法颜阐,同樣在初始的方法中添加資源圖標(biāo)的初始
        /**添加點(diǎn)的圖片資源**/
        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++){
                  
                  /**
                   * 當(dāng)然,此處可以判斷九點(diǎn)的不同的狀態(tài)吓肋,在繪制(正常的凳怨、選中的,錯(cuò)誤的)
                   *
                   * @bitR 為圖片資源的半徑是鬼,因?yàn)楫?huà)筆所繪制的不會(huì)是從中心電繪制肤舞,而是從左上角開(kāi)始繪制,在這里x均蜜,y各減去半徑萨赁,就會(huì)以圖標(biāo)中心的位置開(kāi)始繪制
                   */
                  canvas.drawBitmap(sBitmap,myPoint[i][j].x-bitR,myPoint[i][j].y-bitR,paint);
               }
        }
  }

好了,現(xiàn)在在XML文件中把我們自定義的這個(gè)View添加一下兆龙,運(yùn)行看看,九點(diǎn)的效果就出來(lái)了
實(shí)現(xiàn)思路2(用戶操作)

  • 在用戶手勢(shì)監(jiān)聽(tīng)的方法onTouchEvent中分別有三種狀態(tài)(Down·Move·Up
  • 首先在用戶手指點(diǎn)下的時(shí)候,就要以x紫皇,y生成一個(gè)點(diǎn)慰安,并且將點(diǎn)返回,判斷點(diǎn)的位置是否為九點(diǎn)中任一點(diǎn)的位置聪铺,如果是添加選中的點(diǎn)化焕,并改變點(diǎn)的狀態(tài)
  • 當(dāng)用戶手指移動(dòng)時(shí),同上铃剔,先判斷是否選擇的是九點(diǎn)中任意點(diǎn)撒桨,如果是,在此處再次判斷键兜,次點(diǎn)是否已經(jīng)包含在選中點(diǎn)的集合中凤类,如果沒(méi)有包含,改變點(diǎn)的狀態(tài)并添加
  • 在用戶手指抬起的時(shí)候普气,先判斷所繪制的點(diǎn)的總數(shù)是否大于規(guī)定的最小數(shù)量谜疤,分別以點(diǎn)的不同狀態(tài)顯示所選最小數(shù)是否滿足,最后在判斷现诀,當(dāng)用戶操作屏幕后夷磕,并且選中點(diǎn)的數(shù)量大于0,那么就關(guān)閉繪制狀態(tài)
下面為當(dāng)用戶手指點(diǎn)下并且滑動(dòng)的時(shí)候生成的點(diǎn)仔沿,并且返回為選中的九點(diǎn)的任一點(diǎn)坐桩,沒(méi)選中的返回為null
  /**
   * 返回是否選擇的是點(diǎn)
   */
  private int[] getSelectPoint() {
        
        //MyPoint自定義的點(diǎn)的類 ,用戶手指按下時(shí)以x封锉,y生成的點(diǎn)
        MyPoint begainSelectPoint = new MyPoint(moveX,moveY);
        for (int i = 0;i<myPoint.length;i++){
            for (int j = 0;j<myPoint[i].length;j++){
                 //判斷距離將選擇的點(diǎn)的位置否和一定條件時(shí)绵跷,為選中
                if (myPoint[i][j].distance(begainSelectPoint) < bitR){

                    //定義長(zhǎng)度為2的數(shù)組,返回選中點(diǎn)的X烘浦,Y
                    int[] result = new int[2];
                    result[0] = i;
                    result[1] = j;
                    return result;
                }
            }
        }
        return null;//選中的不是九點(diǎn)的任一點(diǎn)時(shí)
  }
下面上一下onTouchEvent的方法(在此方法中在用戶沒(méi)操作的時(shí)候都要顯示選中點(diǎn)的狀態(tài)抖坪,所以要及時(shí)更新View,可以用this.postInvalidate();方法闷叉,及時(shí)更新)
  @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;//設(shè)置點(diǎn)的狀態(tài)
                      allPoint.add(myPoint[x][y]);//添加點(diǎn)到選擇點(diǎn)的集合
                  }
              }
              break;
          case MotionEvent.ACTION_MOVE:
              if (isDrawing){
                  getSelect = getSelectPoint();
                  if (getSelect != null){
                      x = getSelect[0];
                      y = getSelect[1];
                      if (!allPoint.contains(myPoint[x][y])){//判斷是否已經(jīng)包含此點(diǎn)
                          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(),"至少不少于四點(diǎn)",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();//及時(shí)更新
      return true;
  }
onTouchEvent方法之后就可以繪制線了擦俐,線的繪制是以兩點(diǎn)劃線,并且握侧,每次講第二次選擇的線賦值為初始點(diǎn)蚯瞧,下面給下選中九點(diǎn)的任一點(diǎn),和沒(méi)選中是線的繪制
  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);//此為選中九點(diǎn)時(shí)的劃線的方法
              A = B;
          }
          if (isDrawing){
              drawLines(canvas,A,new MyPoint(moveX,moveY));//當(dāng)處于繪制狀態(tài)時(shí)品擎,沒(méi)有選中時(shí)埋合,劃線就是一手指移動(dòng)而繪制
          }
      }
  }
繪制線的方法,判斷選擇的點(diǎn)的個(gè)數(shù)萄传,繪制不同狀態(tài)的線
  /**
   * 通過(guò)兩點(diǎn)繪制線
   * @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);
      }
  }
用戶操作密碼記錄
  • 上面我們?cè)谟脩舨僮鞯姆椒?code>onTouchEvent中用三種狀態(tài)甚颂,我們只需在用戶按下和移動(dòng)的狀態(tài)中添加判斷的方法,判斷用戶選擇的是當(dāng)前的哪一個(gè)點(diǎn),我們?cè)诮o每一個(gè)點(diǎn)設(shè)置不同的標(biāo)志值振诬,當(dāng)用戶保存時(shí)蹭睡,我們可以將用戶的選擇點(diǎn)的標(biāo)志保存起來(lái)即可(下面上下代碼)
    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");
    }
    }

上面的代碼我們可以生成一個(gè)方法,在用戶按下和移動(dòng)的操作中調(diào)用即可

好了赶么,九宮鎖到此結(jié)束肩豁,有更好思路的請(qǐng)告知,以上文章如有錯(cuò)誤辫呻,請(qǐng)熱情指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末清钥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子放闺,更是在濱河造成了極大的恐慌祟昭,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雄人,死亡現(xiàn)場(chǎng)離奇詭異从橘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)础钠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)恰力,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人旗吁,你說(shuō)我怎么就攤上這事踩萎。” “怎么了很钓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵香府,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我码倦,道長(zhǎng)企孩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任袁稽,我火速辦了婚禮勿璃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘推汽。我一直安慰自己补疑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布歹撒。 她就那樣靜靜地躺著莲组,像睡著了一般。 火紅的嫁衣襯著肌膚如雪暖夭。 梳的紋絲不亂的頭發(fā)上锹杈,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天撵孤,我揣著相機(jī)與錄音,去河邊找鬼嬉橙。 笑死早直,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的市框。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼糕韧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼枫振!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起萤彩,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤粪滤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后雀扶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體杖小,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年愚墓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了予权。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浪册,死狀恐怖扫腺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情村象,我是刑警寧澤笆环,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站厚者,受9級(jí)特大地震影響躁劣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜库菲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一账忘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蝙昙,春花似錦闪萄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至烈拒,卻和暖如春圆裕,著一層夾襖步出監(jiān)牢的瞬間广鳍,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工吓妆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赊时,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓行拢,卻偏偏與公主長(zhǎng)得像祖秒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舟奠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)竭缝。 張土汪:刷leetcod...
    土汪閱讀 12,743評(píng)論 0 33
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 6,397評(píng)論 0 17
  • 首頁(yè) 資訊 文章 資源 小組 相親 登錄 注冊(cè) 首頁(yè) 最新文章 IT 職場(chǎng) 前端 后端 移動(dòng)端 數(shù)據(jù)庫(kù) 運(yùn)維 其他...
    Helen_Cat閱讀 3,869評(píng)論 1 10
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理沼瘫,服務(wù)發(fā)現(xiàn)抬纸,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,070評(píng)論 25 707