圖案鎖屏

最近跟著視頻學(xué)習(xí)了個(gè)圖案解鎖的功能,效果圖如下:

圖案鎖屏.gif

需求如下:
1.第一次的需要設(shè)置鎖屏密碼
2.繪制密碼的時(shí)候密碼必須是五位或者五位以上的
3.繪制錯(cuò)誤的時(shí)候會(huì)提示,并將點(diǎn)和線的狀態(tài)還原成初始狀態(tài)
4.繪制完成的時(shí)候,如果是五位及以上的,比對(duì)密碼摘完,如果一樣則解鎖成功,不一樣就提示“密碼錯(cuò)誤”
具體操作如下
1.初始化點(diǎn)和線的資源

    /**
     * 初始化點(diǎn)
     */
    private void initPoints() {
        //1.獲取布局寬高
        width = getWidth();
        height = getHeight();

        //橫屏和豎屏
        if (width > height) {
            offsetsX = (width - height) / 2;
            width = height;
        } else {
            offssetsY = (height - width) / 2;
            height = width;
        }

        //圖片資源
        pointNormal = BitmapFactory.decodeResource(getResources(), R.drawable.point_normal);
        pointPressed = BitmapFactory.decodeResource(getResources(), R.drawable.point_pressed);
        pointError = BitmapFactory.decodeResource(getResources(), R.drawable.point_error);
        linePressed = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
        lineError = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);

        points[0][0] = new Point((offsetsX + width / 4), (offssetsY + width / 4));
        points[0][1] = new Point((offsetsX + width / 2), (offssetsY + width / 4));
        points[0][2] = new Point((offsetsX + width - width / 4), (offssetsY + width / 4));

        points[1][0] = new Point((offsetsX + width / 4), (offssetsY + width / 2));
        points[1][1] = new Point((offsetsX + width / 2), (offssetsY + width / 2));
        points[1][2] = new Point((offsetsX + width - width / 4), (offssetsY + width / 2));

        points[2][0] = new Point((offsetsX + width / 4), (offssetsY + width - width / 4));
        points[2][1] = new Point((offsetsX + width / 2), (offssetsY + width - width / 4));
        points[2][2] = new Point((offsetsX + width - width / 4), (offssetsY + width - width / 4));

        mPointRadius = pointNormal.getWidth() / 2;

        // 設(shè)置密碼
        int index = 1;
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                points[i][j].index = index;
                index++;
            }
        }
        isInit = true;
    }

2.繪制點(diǎn)

    /**
     * 將點(diǎn)繪制到畫(huà)布
     *
     * @param canvas
     */
    private void points2Canvas(Canvas canvas) {
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                Point point = points[i][j];
                if (point.state == Point.STATE_NORMAL) {
                    canvas.drawBitmap(pointNormal, point.x - mPointRadius, point.y - mPointRadius, paint);
                } else if (point.state == Point.STATE_PRESSED) {
                    canvas.drawBitmap(pointPressed, point.x - mPointRadius, point.y - mPointRadius, paint);
                } else {
                    canvas.drawBitmap(pointError, point.x - mPointRadius, point.y - mPointRadius, paint);
                }
            }
        }
    }

3.movingX傻谁,movingY記錄觸發(fā)的位置孝治,isFinish記錄繪制圖案是否結(jié)束,isSelected記錄九宮格的點(diǎn)是否被選中审磁,只要我們沒(méi)有觸發(fā)onTouchEvent方法中的 MotionEvent.ACTION_UP谈飒,就沒(méi)有結(jié)束,只有手指抬起的時(shí)候才結(jié)束态蒂。
手指按下的時(shí)候需要判斷當(dāng)前按下的位置杭措,是不是九宮格的點(diǎn),在按下的時(shí)候钾恢,將所有的點(diǎn)和線還原

            case MotionEvent.ACTION_DOWN:
                //重新繪制
                resetPoint();
                point = checkSelectPoint();
                if (point != null) {
                    isSelected = true;
                }
                break;
    /**
     * 檢查點(diǎn)是否選中
     *
     * @return
     */
    private Point checkSelectPoint() {
        for (int i = 0; i < points.length; i++) {
            for (int j = 0; j < points[i].length; j++) {
                Point point = points[i][j];
                if (with(point.x, point.y, mPointRadius, movingX, movingY)) {
                    return point;
                }
            }
        }
        return null;
    }
    /**
     * 是否重合
     *
     * @param poinX   參考點(diǎn)的X
     * @param pointY  參考點(diǎn)的Y
     * @param r       圓的半徑
     * @param movingX 移動(dòng)點(diǎn)的X
     * @param movingY 移動(dòng)點(diǎn)的Y
     * @return 是否重合
     */
    private static boolean with(float poinX, float pointY, float r, float movingX, float movingY) {
        return Math.sqrt((poinX - movingX) * (poinX - movingX) + (pointY - movingY) * (pointY - movingY)) < r;
    }
    /**
     * 重置
     */
    public void resetPoint() {
        //將點(diǎn)的狀態(tài)還原
        for (Point point : pointList) {
            point.state = Point.STATE_NORMAL;
        }
        pointList.clear();
    }

在手指移動(dòng)的時(shí)候手素,如果點(diǎn)被選中,得到被選中的九宮格的點(diǎn)

                if (isSelected) {
                    point = checkSelectPoint();
                    isMoveButNotPoint = true;
                }

手指抬起的時(shí)候

                isFinish = true;
                isSelected = false;

在onTouchEvent的最后瘩蚪,繪制沒(méi)有結(jié)束泉懦,點(diǎn)被選中,判斷這個(gè)點(diǎn)是否在已選中的點(diǎn)的集合內(nèi)疹瘦,不在的話添加進(jìn)去崩哩,在的話,移動(dòng)但不是九宮格的點(diǎn)的標(biāo)志isMoveButNotPoint為true

        //選中重復(fù)檢查
        if (!isFinish && isSelected && point != null) {
            if (checkCrossPoint(point)) {  //交叉點(diǎn)
                isMoveButNotPoint = true;
            } else {   //非交叉點(diǎn)(新的點(diǎn))
                point.state = Point.STATE_PRESSED;
                pointList.add(point);
            }
        }

繪制結(jié)束,如果只有一個(gè)點(diǎn)則繪制不成立邓嘹,繪制的點(diǎn)的個(gè)數(shù) 在2-5內(nèi)酣栈,繪制錯(cuò)誤,5個(gè)及以上表示成功汹押,但不是真的成功钉嘹,因?yàn)橐椭霸O(shè)置的點(diǎn)進(jìn)行對(duì)比,一樣才表示成功

        //繪制結(jié)束
        if (isFinish) {
            if (pointList.size() == 1) {//繪制不成立
                resetPoint();
            } else if (pointList.size() < pointSize && pointList.size() >= 2) {//繪制錯(cuò)誤
                errPoint();
                if (onPatterChangeListener != null) {
                    onPatterChangeListener.onPatterChange(null);
                }
                onResultRest();
            } else {//繪制成功
                if (onPatterChangeListener != null) {
                    String passwordStr = "";
                    for (int i = 0; i < pointList.size(); i++) {
                        passwordStr = passwordStr + pointList.get(i).index;
                    }
                    if (!TextUtils.isEmpty(passwordStr)) {
                        onPatterChangeListener.onPatterChange(passwordStr);
                    }
                }
                onResultRest();
            }
        }

繪制線

        if (pointList.size() > 0) {
            Point startPoint = pointList.get(0);
            //繪制九宮格坐標(biāo)里的點(diǎn)
            for (int i = 0; i < pointList.size(); i++) {
                Point endPoint = pointList.get(i);
                lineToCanvas(canvas, startPoint, endPoint);
                startPoint = endPoint;
            }
            //繪制九宮格坐標(biāo)以外的點(diǎn)
            if (isMoveButNotPoint) {
                lineToCanvas(canvas, startPoint, new Point(movingX, movingY));
            }
        }
    /**
     * 將線繪制到畫(huà)布上
     *
     * @param canvas     畫(huà)布
     * @param startPoint 開(kāi)始的點(diǎn)
     * @param endPoint   結(jié)束的點(diǎn)
     */
    private void lineToCanvas(Canvas canvas, Point startPoint, Point endPoint) {
        float lineLength = (float) twoPointDistance(startPoint, endPoint);
        float degree = getDegrees(startPoint, endPoint);
        canvas.rotate(degree, startPoint.x, startPoint.y);  //旋轉(zhuǎn)
        if (startPoint.state == Point.STATE_PRESSED) {  //按下的狀態(tài)
            //設(shè)置線的縮放比例,在這里線是往一個(gè)方向縮放的,即x軸,我們只需要設(shè)置x軸的縮放比例即可,y軸默認(rèn)為1
            matrix.setScale(lineLength / linePressed.getWidth(), 1);
            matrix.postTranslate(startPoint.x - linePressed.getWidth() / 2, startPoint.y - linePressed.getHeight() / 2);
            canvas.drawBitmap(linePressed, matrix, paint);
        } else {   //錯(cuò)誤的狀態(tài)
            matrix.setScale(lineLength / lineError.getWidth(), 1);
            matrix.postTranslate(startPoint.x - lineError.getWidth() / 2, startPoint.y - lineError.getHeight() / 2);
            canvas.drawBitmap(lineError, matrix, paint);
        }
        canvas.rotate(-degree, startPoint.x, startPoint.y);  //把旋轉(zhuǎn)的角度轉(zhuǎn)回來(lái)
    }

點(diǎn)和線就繪制成功了鲸阻,下面寫(xiě)個(gè)監(jiān)聽(tīng)

    /**
     * 圖案監(jiān)聽(tīng)器
     */
    public interface OnPatterChangeListener {
        void onPatterChange(String passwordStr);

        /**
         * 圖案重新繪制
         *
         * @param isStart
         */
        void onPatterStart(boolean isStart);
    }

    private OnPatterChangeListener onPatterChangeListener;

    public void setOnPatterChangeListener(OnPatterChangeListener onPatterChangeListener) {
        this.onPatterChangeListener = onPatterChangeListener;
    }

在繪制出錯(cuò)或者繪制成功的時(shí)候調(diào)用onPatterChange方法,在開(kāi)始繪制的時(shí)候調(diào)用onPatterStart方法缨睡。
在繪制成功和繪制出錯(cuò)的時(shí)候?qū)Ⅻc(diǎn)和線的還原成初始狀態(tài)

    private void onResultRest() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                resetPoint();
                postInvalidate();
            }
        }, 1000);
    }

至此鸟悴,給各位大佬奉上項(xiàng)目地址:
https://github.com/diudiuhf/SatelliteMenu

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市奖年,隨后出現(xiàn)的幾起案子细诸,更是在濱河造成了極大的恐慌,老刑警劉巖陋守,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件震贵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡水评,警方通過(guò)查閱死者的電腦和手機(jī)猩系,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)中燥,“玉大人寇甸,你說(shuō)我怎么就攤上這事×粕妫” “怎么了拿霉?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)咱扣。 經(jīng)常有香客問(wèn)我绽淘,道長(zhǎng),這世上最難降的妖魔是什么闹伪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任沪铭,我火速辦了婚禮,結(jié)果婚禮上偏瓤,老公的妹妹穿的比我還像新娘伦意。我一直安慰自己,他們只是感情好硼补,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布驮肉。 她就那樣靜靜地躺著,像睡著了一般已骇。 火紅的嫁衣襯著肌膚如雪离钝。 梳的紋絲不亂的頭發(fā)上票编,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音卵渴,去河邊找鬼慧域。 笑死,一個(gè)胖子當(dāng)著我的面吹牛浪读,可吹牛的內(nèi)容都是我干的昔榴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碘橘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼互订!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起痘拆,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤仰禽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后纺蛆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吐葵,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年桥氏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了温峭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡字支,死狀恐怖诚镰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情祥款,我是刑警寧澤清笨,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站刃跛,受9級(jí)特大地震影響抠艾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜桨昙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一检号、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛙酪,春花似錦齐苛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春玛痊,著一層夾襖步出監(jiān)牢的瞬間汰瘫,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工擂煞, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留混弥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓对省,卻偏偏與公主長(zhǎng)得像蝗拿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蒿涎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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