教你寫一個九宮格鎖屏View

Loren1994發表於2017-10-21

Android自定義控制元件系列之:鎖屏頁

介紹

  • 翻閱以前寫過的demo,發現在1.52225年前擼過一個仿鎖屏功能的自定義View,特此記錄。

基本思路

  • 分析一下,android鎖屏一般為九宮格,將螢幕九等分,以每部分的中點為圓心畫圓,每個圓有預設狀態和連線狀態以及錯誤狀態,根據觸控區域判斷觸控的點,在onDraw裡畫出點和線,在需要的地方設定Paint的顏色等屬性後postInvalidate一下,這樣來實現點的不同狀態的顯示。每連線一個點都將此點的下標存入陣列,可在activity設定開鎖密碼,連線完後判斷是否正確。

程式碼實現

給這個view起個低調且奢華的名字,繼承View,然後開擼。

特別注意:名字不屌,View寫不好。:happy:

  • 計算9個點的座標
  int width = MeasureSpec.getSize(widthMeasureSpec);
  int height = MeasureSpec.getSize(heightMeasureSpec);
  //鎖屏3x3點矩陣
  widthArea = width / 3;
  heightArea = height / 3;
  CIRCLE_RADIUS = widthArea / 4;//設定半徑
  //根據螢幕設定9個座標點
  a[0][0] = widthArea / 2;
  a[1][0] = widthArea * 2 * 0.75f;
  a[2][0] = widthArea * 3 * 5 / 6;
  a[3][0] = widthArea / 2;
  a[4][0] = widthArea * 2 * 0.75f;
  a[5][0] = widthArea * 3 * 5 / 6;
  a[6][0] = widthArea / 2;
  a[7][0] = widthArea * 2 * 0.75f;
  a[8][0] = widthArea * 3 * 5 / 6;
  a[0][1] = heightArea / 2;
  a[1][1] = heightArea / 2;
  a[2][1] = heightArea / 2;
  a[3][1] = heightArea * 2 * 0.75f;
  a[4][1] = heightArea * 2 * 0.75f;
  a[5][1] = heightArea * 2 * 0.75f;
  a[6][1] = heightArea * 3 * 5 / 6;
  a[7][1] = heightArea * 3 * 5 / 6;
  a[8][1] = heightArea * 3 * 5 / 6;複製程式碼
  • onDraw方法
protected void onDraw(Canvas canvas) {
        //畫出已連線的點
        for (int i = 0; i < positionArr.size(); i++) {
            if (curCircle.contains(i)) {
                canvas.drawCircle(positionArr.get(i).x, positionArr.get(i).y, CIRCLE_RADIUS, mClickPaint);
            } else {
                canvas.drawCircle(positionArr.get(i).x, positionArr.get(i).y, CIRCLE_RADIUS, mPaint);
            }
        }
        //已連線的點之間的線
        for (int i = 0; i < curCircle.size(); i++) {
            if (i + 1 < curCircle.size()) {
                canvas.drawLine(positionArr.get(curCircle.get(i)).x, positionArr.get(curCircle.get(i)).y, positionArr.get(curCircle.get(i + 1)).x, positionArr.get(curCircle.get(i + 1)).y, mLinePaint);
            }
        }
        //最後的點與觸控位置之間的線
        if (moveX != 0 && moveY != 0 && curCircle.size() > 0 && curCircle.size() < 9 && isTouch) {
            canvas.drawLine(positionArr.get(curCircle.get(curCircle.size() - 1)).x, positionArr.get(curCircle.get(curCircle.size() - 1)).y, moveX, moveY, mLinePaint);
        }
}複製程式碼
  • onTouchEvent方法
public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_UP:
                checkPassword();
                break;
            case MotionEvent.ACTION_MOVE:
                moveX = event.getX();
                moveY = event.getY();
                //判斷觸控點下標
                int pos = whichCircle(event.getX(), event.getY());
                //存入陣列
                if (pos != -1 && !curCircle.contains(pos)) {
                    curCircle.add(pos);
                    System.out.println(pos);
                }
                postInvalidate();
                break;
        }
        return true;
}複製程式碼
  • 判斷觸控點
private int whichCircle(float x, float y) {
        int position = -1;
        for (int i = 0; i < positionArr.size(); i++) {
            if (Math.abs(x - positionArr.get(i).x) 
                < CIRCLE_RADIUS && Math.abs(y - positionArr.get(i).y) <CIRCLE_RADIUS) {
                position = i;
            }
        }
        return position;
}複製程式碼
  • 根據已連線的陣列去判斷密碼是否正確,然後回撥
private void checkPassword() {
        StringBuilder pwd = new StringBuilder();
        for (Integer pos : curCircle) {
            pwd.append(pos).append("");
        }
        //連線點數小於等於2則忽略此次連線
        if (curCircle.size() > 2) {
            listener.checkListener(pwd.toString());
            if (!password.equals(pwd.toString())) {
                mLinePaint.setColor(Color.RED);
                mClickPaint.setColor(Color.RED);
                postInvalidate();
                isTouch = false;
                postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        reset();
                    }
                }, 1000);
            }
        } else {
              //重置View
            reset();
        }
}複製程式碼

原始碼地址

控制元件:t.cn/Rp4UZHK 原始碼附有註釋

用法:t.cn/Rp4b4OV

最終效果

最後祝看過的人進步~

相關文章