Android中图案锁的实现

原文地址:http://blog.csdn.net/liusiqian0209/article/details/50372448

很多品牌的Android手机都实现了图案解锁屏幕的功能,有些应用程序出于保护的目的也使用了图案锁(比如支付宝),本文将介绍一种图案锁的实现方式,这种实现的一个优势在于方便扩展和自定义,我们先看一下效果图。

  首先是连线阶段,整个连线为两部分:第一部分是点和点之间的固定线段,第二部分是最后一个点到鼠标移动位置的自由线段。

  接下来是连线结束之后,需要判断图案是否正确,我这里暂时写死的Z字形为正确图案,实际应用时需要记录用户的输入为设置的图案密码。



  首先我们考虑在哪里完成点和线的绘图。通常我们想到的是写一个自定义的View(即继承自View类),添加onTouchEvent进行控制,同时覆写onDraw()方法,完成绘制。不过我这里没有采用这种方式,考虑到onTouchEvent只能接收在View之上的触摸事件,从上面第一张图中可以看出,如果文字和自定义View平铺摆放的话,那么当手指滑动到文字上面的时候,已经超出了自定义View的范围,因此无法响应触摸事件。虽说有一种补救方式,就是让其他控件和自定义View叠在一起,即摆放在一个FrameLayout里面,不过帧布局对控件位置的控制不像RelativeLayout这样灵活,因此我的实现方式是自定义RelativeLayout,并且在dispatchDraw()方法里,完成点和线的绘制。dispatchDraw()会在布局绘制子控件时调用,具体的可以参考谷歌官方文档。

  首先需要有一个类来记录九个圆点的基本信息。我们可以视为这九个圆是分布于3*3的方格子里面,其中每一个圆位于方格子的中心,在绘制这些圆时,有以下基本信息是要知道的:

1、这些方格子的位置(左上角的X,Y坐标)

2、方格子的边长有多大?

3、方格子的边到圆的边有多大的间隔?

4、圆心的位置(圆心X,Y坐标)

5、圆的半径是多少?

6、这个圆当前应该显示什么颜色?(即圆点的状态)

7、由于我们不可能记录图案整体,而是记录连接点的顺序,那么这个圆所表示的密码值是多少?

  不过上面这7个值是相互依赖的,比如我知道了1和2,就能知道4;知道了2和3,就能知道5。因此,在定义这些值的时候,应当让用户提供充分但不冲突的信息(比如我这里从外部获取的是1、2、3、6、7,而4和5是算出来的)。我在实现的时候,把定义下来就再也用不到的信息写在了一个类里面,把绘制点时还需要获取的信息写在了另一个类里面,并且这个类提供了一些外部调用的方法(实际上这两个类合二为一是完全合理的),代码如下。

<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.liusiqian.patternlock;

<span class="hljs-javadoc">/**
 * Créé par liusiqian 15/12/18.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PatternPointBase</span>
{</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> centerX;     <span class="hljs-comment">//圆心X</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> centerY;     <span class="hljs-comment">//圆心Y</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> radius;      <span class="hljs-comment">//半径</span>
    <span class="hljs-keyword">protected</span> String tag;      <span class="hljs-comment">//密码标签</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> status;         <span class="hljs-comment">//状态</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_NORMAL = <span class="hljs-number">0</span>;       <span class="hljs-comment">//正常</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_SELECTED = <span class="hljs-number">1</span>;     <span class="hljs-comment">//选中</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STATE_ERROR = <span class="hljs-number">2</span>;        <span class="hljs-comment">//错误</span>

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCenterX</span>()
    {
        <span class="hljs-keyword">return</span> centerX;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getCenterY</span>()
    {
        <span class="hljs-keyword">return</span> centerY;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isPointArea</span>(<span class="hljs-keyword">double</span> x, <span class="hljs-keyword">double</span> y)
    {
        <span class="hljs-keyword">double</span> len = Math.sqrt(Math.pow(centerX - x, <span class="hljs-number">2</span>) + Math.pow(centerY - y, <span class="hljs-number">2</span>));
        <span class="hljs-keyword">return</span> radius > len;
    }

    <span class="hljs-keyword">public</span> String <span class="hljs-title">getTag</span>()
    {
        <span class="hljs-keyword">return</span> tag;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getRadius</span>()
    {
        <span class="hljs-keyword">return</span> radius;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li></ul>
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.liusiqian.patternlock;

<span class="hljs-javadoc">/**
 * Créé par liusiqian 15/12/18.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PatternPoint</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">PatternPointBase</span>
{</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> MIN_SIDE = <span class="hljs-number">20</span>;        <span class="hljs-comment">//最小边长</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> MIN_PADDING = <span class="hljs-number">4</span>;        <span class="hljs-comment">//最小间隔</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> MIN_RADIUS = <span class="hljs-number">6</span>;        <span class="hljs-comment">//最小半径</span>

    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">int</span> left, top, side, padding;     <span class="hljs-comment">//side:边长</span>

    <span class="hljs-keyword">public</span> <span class="hljs-title">PatternPoint</span>(<span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> top, <span class="hljs-keyword">int</span> side, <span class="hljs-keyword">int</span> padding, String tag)
    {
        <span class="hljs-keyword">this</span>.left = left;
        <span class="hljs-keyword">this</span>.top = top;
        <span class="hljs-keyword">this</span>.tag = tag;

        <span class="hljs-keyword">if</span> (side < MIN_SIDE)
        {
            side = MIN_SIDE;
        }
        <span class="hljs-keyword">this</span>.side = side;

        <span class="hljs-keyword">if</span> (padding < MIN_PADDING)
        {
            padding = MIN_PADDING;
        }

        radius = side / <span class="hljs-number">2</span> - padding;
        <span class="hljs-keyword">if</span> (radius < MIN_RADIUS)
        {
            radius = MIN_RADIUS;
            padding = side / <span class="hljs-number">2</span> - radius;
        }
        <span class="hljs-keyword">this</span>.padding = padding;
        centerX = left + side / <span class="hljs-number">2</span>;
        centerY = top + side / <span class="hljs-number">2</span>;
        status = STATE_NORMAL;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li></ul>

  可以看到,在基类里面定义了圆点的状态常量。此外还提供了一个方法叫做isPointArea(),这个方法用于判断对于给定的一个点,它是否在这个圆之内。我们在进行连线时,如果经过了一个点,则需要把它连接起来,这时需要用到这个函数。

  接下来是这个扩展的RelativeLayout,这里先给出整个类的代码,然后再逐步解释。

<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.liusiqian.patternlock;

<span class="hljs-keyword">import</span> android.content.Context;
<span class="hljs-keyword">import</span> android.graphics.Canvas;
<span class="hljs-keyword">import</span> android.graphics.Paint;
<span class="hljs-keyword">import</span> android.os.Handler;
<span class="hljs-keyword">import</span> android.util.AttributeSet;
<span class="hljs-keyword">import</span> android.view.MotionEvent;
<span class="hljs-keyword">import</span> android.widget.RelativeLayout;

<span class="hljs-keyword">import</span> java.util.ArrayList;

<span class="hljs-javadoc">/**
 * Créé par liusiqian 15/12/18.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PatternLockLayout</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">RelativeLayout</span>
{</span>
    <span class="hljs-keyword">public</span> <span class="hljs-title">PatternLockLayout</span>(Context context)
    {
        <span class="hljs-keyword">super</span>(context);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-title">PatternLockLayout</span>(Context context, AttributeSet attrs)
    {
        <span class="hljs-keyword">super</span>(context, attrs);
    }

    <span class="hljs-keyword">public</span> <span class="hljs-title">PatternLockLayout</span>(Context context, AttributeSet attrs, <span class="hljs-keyword">int</span> defStyleAttr)
    {
        <span class="hljs-keyword">super</span>(context, attrs, defStyleAttr);
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> hasinit;                <span class="hljs-comment">//初始化是否完成</span>
    <span class="hljs-keyword">private</span> PatternPoint[] points = <span class="hljs-keyword">new</span> PatternPoint[<span class="hljs-number">9</span>];        <span class="hljs-comment">//九个圆圈对象</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> width, height, side;                        <span class="hljs-comment">//布局可用宽,布局可用高,小方格子的边长</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> sidePadding, topBottomPadding;      <span class="hljs-comment">//侧边和上下边预留空间</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> startLine;      <span class="hljs-comment">//是否开始连线</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> errorMode;      <span class="hljs-comment">//连线是否使用表示错误的颜色</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> drawEnd;        <span class="hljs-comment">//是否已经抬手</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> resetFinished;  <span class="hljs-comment">//重置是否已经完成(是否可以进行下一次连线)</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">float</span> moveX, moveY;     <span class="hljs-comment">//手指位置</span>
    <span class="hljs-keyword">private</span> ArrayList<PatternPoint> selectedPoints = <span class="hljs-keyword">new</span> ArrayList<>();     <span class="hljs-comment">//所有已经选中的点</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> PAINT_COLOR_NORMAL = <span class="hljs-number">0xffcccccc</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> PAINT_COLOR_SELECTED = <span class="hljs-number">0xff00dd00</span>;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> PAINT_COLOR_ERROR = <span class="hljs-number">0xffdd0000</span>;

    <span class="hljs-keyword">private</span> Handler mHandler;

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dispatchDraw</span>(Canvas canvas)
    {
        <span class="hljs-keyword">super</span>.dispatchDraw(canvas);
        <span class="hljs-keyword">if</span> (!hasinit)
        {
            <span class="hljs-comment">//暂时写死,后面通过XML设置</span>
            sidePadding = <span class="hljs-number">40</span>;
            topBottomPadding = <span class="hljs-number">40</span>;
            initPoints();
            resetFinished = <span class="hljs-keyword">true</span>;
        }

        drawCircle(canvas);
        drawLine(canvas);
    }

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">onTouchEvent</span>(MotionEvent event)
    {
        moveX = event.getX();
        moveY = event.getY();

        <span class="hljs-keyword">switch</span> (event.getAction())
        {
            <span class="hljs-keyword">case</span> MotionEvent.ACTION_DOWN:
            {
                <span class="hljs-keyword">int</span> index = whichPointArea();
                <span class="hljs-keyword">if</span> (-<span class="hljs-number">1</span> != index && resetFinished)
                {
                    addSelectedPoint(index);
                    startLine = <span class="hljs-keyword">true</span>;
                }
            }
            <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> MotionEvent.ACTION_MOVE:
            {
                <span class="hljs-keyword">if</span> (startLine && resetFinished)
                {
                    <span class="hljs-keyword">int</span> index = whichPointArea();
                    <span class="hljs-keyword">if</span> (-<span class="hljs-number">1</span> != index && points[index].status == PatternPointBase.STATE_NORMAL)
                    {
                        <span class="hljs-comment">//查看是否有中间插入点</span>
                        insertPointIfNeeds(index);
                        <span class="hljs-comment">//增加此点到队列中</span>
                        addSelectedPoint(index);
                    }
                }
            }
            <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> MotionEvent.ACTION_UP:
            {
                <span class="hljs-keyword">if</span> (startLine && resetFinished)
                {
                    resetFinished = <span class="hljs-keyword">false</span>;
                    <span class="hljs-keyword">int</span> delay = processFinish();
                    mHandler.postDelayed(<span class="hljs-keyword">new</span> Runnable()
                    {
                        <span class="hljs-annotation">@Override</span>
                        <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>()
                        {
                            reset();
                        }
                    }, delay);
                }
            }
            <span class="hljs-keyword">break</span>;
        }

        invalidate();

        <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAllSelectedPointsError</span>()
    {
        errorMode = <span class="hljs-keyword">true</span>;
        <span class="hljs-keyword">for</span> (PatternPoint point : selectedPoints)
        {
            point.status = PatternPointBase.STATE_ERROR;
        }
        invalidate();
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">reset</span>()
    {
        <span class="hljs-keyword">for</span> (PatternPoint point : points)
        {
            point.status = PatternPointBase.STATE_NORMAL;
        }
        selectedPoints.clear();
        startLine = <span class="hljs-keyword">false</span>;
        errorMode = <span class="hljs-keyword">false</span>;
        drawEnd = <span class="hljs-keyword">false</span>;
        <span class="hljs-keyword">if</span> (listener != <span class="hljs-keyword">null</span>)
        {
            listener.onReset();
        }
        resetFinished = <span class="hljs-keyword">true</span>;
        invalidate();
    }

    <span class="hljs-comment">//返回值为reset延迟的毫秒数</span>
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">processFinish</span>()
    {
        drawEnd = <span class="hljs-keyword">true</span>;
        <span class="hljs-keyword">if</span> (selectedPoints.size() < <span class="hljs-number">2</span>)
        {
            <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
        }
        <span class="hljs-keyword">else</span>            <span class="hljs-comment">//长度过短、密码错误的判断留给外面</span>
        {
            <span class="hljs-keyword">int</span> size = selectedPoints.size();
            StringBuilder sbPassword = <span class="hljs-keyword">new</span> StringBuilder();
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < size; i++)
            {
                sbPassword.append(selectedPoints.get(i).tag);
            }
            <span class="hljs-keyword">if</span> (listener != <span class="hljs-keyword">null</span>)
            {
                listener.onFinish(sbPassword.toString(), size);
            }
            <span class="hljs-keyword">return</span> <span class="hljs-number">2000</span>;
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OnPatternStateListener</span>
    {</span>
        <span class="hljs-keyword">void</span> onFinish(String password, <span class="hljs-keyword">int</span> sizeOfPoints);

        <span class="hljs-keyword">void</span> onReset();
    }

    <span class="hljs-keyword">private</span> OnPatternStateListener listener;

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setOnPatternStateListener</span>(OnPatternStateListener listener)
    {
        <span class="hljs-keyword">this</span>.listener = listener;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertPointIfNeeds</span>(<span class="hljs-keyword">int</span> curIndex)
    {
        <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span>[][] middleNumMatrix = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[][]{{-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>}, {-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>}, {<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">5</span>}, {-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>}, {-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>}, {-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>}, {<span class="hljs-number">3</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">7</span>}, {-<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>}, {<span class="hljs-number">4</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">7</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>}};

        <span class="hljs-keyword">int</span> selectedSize = selectedPoints.size();
        <span class="hljs-keyword">if</span> (selectedSize > <span class="hljs-number">0</span>)
        {
            <span class="hljs-keyword">int</span> lastIndex = Integer.parseInt(selectedPoints.get(selectedSize - <span class="hljs-number">1</span>).tag) - <span class="hljs-number">1</span>;
            <span class="hljs-keyword">int</span> middleIndex = middleNumMatrix[lastIndex][curIndex];
            <span class="hljs-keyword">if</span> (middleIndex != -<span class="hljs-number">1</span> && (points[middleIndex].status == PatternPointBase.STATE_NORMAL) && (points[curIndex].status == PatternPointBase.STATE_NORMAL))
            {
                addSelectedPoint(middleIndex);
            }

        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addSelectedPoint</span>(<span class="hljs-keyword">int</span> index)
    {
        selectedPoints.add(points[index]);
        points[index].status = PatternPointBase.STATE_SELECTED;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">whichPointArea</span>()
    {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">9</span>; i++)
        {
            <span class="hljs-keyword">if</span> (points[i].isPointArea(moveX, moveY))
            {
                <span class="hljs-keyword">return</span> i;
            }
        }
        <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawLine</span>(Canvas canvas)
    {
        Paint paint = getCirclePaint(errorMode ? PatternPoint.STATE_ERROR : PatternPoint.STATE_SELECTED);
        paint.setStrokeWidth(<span class="hljs-number">15</span>);

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < selectedPoints.size(); i++)
        {
            <span class="hljs-keyword">if</span> (i != selectedPoints.size() - <span class="hljs-number">1</span>)      <span class="hljs-comment">//连接线</span>
            {
                PatternPoint first = selectedPoints.get(i);
                PatternPoint second = selectedPoints.get(i + <span class="hljs-number">1</span>);
                canvas.drawLine(first.getCenterX(), first.getCenterY(),
                        second.getCenterX(), second.getCenterY(), paint);
            }
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!drawEnd)                        <span class="hljs-comment">//自由线,抬手之后就不用画了</span>
            {
                PatternPoint last = selectedPoints.get(i);
                canvas.drawLine(last.getCenterX(), last.getCenterY(),
                        moveX, moveY, paint);
            }
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">drawCircle</span>(Canvas canvas)
    {
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">9</span>; i++)
        {
            PatternPoint point = points[i];
            Paint paint = getCirclePaint(point.status);
            canvas.drawCircle(point.getCenterX(), point.getCenterY(), points[i].getRadius(), paint);
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initPoints</span>()
    {
        width = getWidth() - getPaddingLeft() - getPaddingRight() - sidePadding * <span class="hljs-number">2</span>;
        height = getHeight() - getPaddingTop() - getPaddingBottom() - topBottomPadding * <span class="hljs-number">2</span>;

        <span class="hljs-comment">//使用时暂定强制竖屏(即认定height>width)</span>
        <span class="hljs-keyword">int</span> left, top;
        left = getPaddingLeft() + sidePadding;
        top = height + getPaddingTop() + topBottomPadding - width;
        side = width / <span class="hljs-number">3</span>;

        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">3</span>; i++)
        {
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j < <span class="hljs-number">3</span>; j++)
            {
                <span class="hljs-keyword">int</span> leftX = left + j * side;
                <span class="hljs-keyword">int</span> topY = top + i * side;
                <span class="hljs-keyword">int</span> index = i * <span class="hljs-number">3</span> + j;
                points[index] = <span class="hljs-keyword">new</span> PatternPoint(leftX, topY, side, side / <span class="hljs-number">3</span>, String.valueOf(index + <span class="hljs-number">1</span>));
            }
        }

        mHandler = <span class="hljs-keyword">new</span> Handler();

        hasinit = <span class="hljs-keyword">true</span>;
    }

    <span class="hljs-keyword">private</span> Paint <span class="hljs-title">getCirclePaint</span>(<span class="hljs-keyword">int</span> state)
    {
        Paint paint = <span class="hljs-keyword">new</span> Paint();
        <span class="hljs-keyword">switch</span> (state)
        {
            <span class="hljs-keyword">case</span> PatternPoint.STATE_NORMAL:
                paint.setColor(PAINT_COLOR_NORMAL);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> PatternPoint.STATE_SELECTED:
                paint.setColor(PAINT_COLOR_SELECTED);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">case</span> PatternPoint.STATE_ERROR:
                paint.setColor(PAINT_COLOR_ERROR);
                <span class="hljs-keyword">break</span>;
            <span class="hljs-keyword">default</span>:
                paint.setColor(PAINT_COLOR_NORMAL);
        }
        <span class="hljs-keyword">return</span> paint;
    }
}
</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li><li>151</li><li>152</li><li>153</li><li>154</li><li>155</li><li>156</li><li>157</li><li>158</li><li>159</li><li>160</li><li>161</li><li>162</li><li>163</li><li>164</li><li>165</li><li>166</li><li>167</li><li>168</li><li>169</li><li>170</li><li>171</li><li>172</li><li>173</li><li>174</li><li>175</li><li>176</li><li>177</li><li>178</li><li>179</li><li>180</li><li>181</li><li>182</li><li>183</li><li>184</li><li>185</li><li>186</li><li>187</li><li>188</li><li>189</li><li>190</li><li>191</li><li>192</li><li>193</li><li>194</li><li>195</li><li>196</li><li>197</li><li>198</li><li>199</li><li>200</li><li>201</li><li>202</li><li>203</li><li>204</li><li>205</li><li>206</li><li>207</li><li>208</li><li>209</li><li>210</li><li>211</li><li>212</li><li>213</li><li>214</li><li>215</li><li>216</li><li>217</li><li>218</li><li>219</li><li>220</li><li>221</li><li>222</li><li>223</li><li>224</li><li>225</li><li>226</li><li>227</li><li>228</li><li>229</li><li>230</li><li>231</li><li>232</li><li>233</li><li>234</li><li>235</li><li>236</li><li>237</li><li>238</li><li>239</li><li>240</li><li>241</li><li>242</li><li>243</li><li>244</li><li>245</li><li>246</li><li>247</li><li>248</li><li>249</li><li>250</li><li>251</li><li>252</li><li>253</li><li>254</li><li>255</li><li>256</li><li>257</li><li>258</li><li>259</li><li>260</li><li>261</li><li>262</li><li>263</li><li>264</li><li>265</li><li>266</li><li>267</li><li>268</li><li>269</li><li>270</li><li>271</li><li>272</li><li>273</li><li>274</li><li>275</li><li>276</li><li>277</li><li>278</li><li>279</li><li>280</li><li>281</li><li>282</li><li>283</li><li>284</li><li>285</li><li>286</li><li>287</li><li>288</li><li>289</li><li>290</li><li>291</li><li>292</li><li>293</li><li>294</li><li>295</li><li>296</li><li>297</li><li>298</li><li>299</li><li>300</li><li>301</li><li>302</li><li>303</li><li>304</li><li>305</li><li>306</li><li>307</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li><li>151</li><li>152</li><li>153</li><li>154</li><li>155</li><li>156</li><li>157</li><li>158</li><li>159</li><li>160</li><li>161</li><li>162</li><li>163</li><li>164</li><li>165</li><li>166</li><li>167</li><li>168</li><li>169</li><li>170</li><li>171</li><li>172</li><li>173</li><li>174</li><li>175</li><li>176</li><li>177</li><li>178</li><li>179</li><li>180</li><li>181</li><li>182</li><li>183</li><li>184</li><li>185</li><li>186</li><li>187</li><li>188</li><li>189</li><li>190</li><li>191</li><li>192</li><li>193</li><li>194</li><li>195</li><li>196</li><li>197</li><li>198</li><li>199</li><li>200</li><li>201</li><li>202</li><li>203</li><li>204</li><li>205</li><li>206</li><li>207</li><li>208</li><li>209</li><li>210</li><li>211</li><li>212</li><li>213</li><li>214</li><li>215</li><li>216</li><li>217</li><li>218</li><li>219</li><li>220</li><li>221</li><li>222</li><li>223</li><li>224</li><li>225</li><li>226</li><li>227</li><li>228</li><li>229</li><li>230</li><li>231</li><li>232</li><li>233</li><li>234</li><li>235</li><li>236</li><li>237</li><li>238</li><li>239</li><li>240</li><li>241</li><li>242</li><li>243</li><li>244</li><li>245</li><li>246</li><li>247</li><li>248</li><li>249</li><li>250</li><li>251</li><li>252</li><li>253</li><li>254</li><li>255</li><li>256</li><li>257</li><li>258</li><li>259</li><li>260</li><li>261</li><li>262</li><li>263</li><li>264</li><li>265</li><li>266</li><li>267</li><li>268</li><li>269</li><li>270</li><li>271</li><li>272</li><li>273</li><li>274</li><li>275</li><li>276</li><li>277</li><li>278</li><li>279</li><li>280</li><li>281</li><li>282</li><li>283</li><li>284</li><li>285</li><li>286</li><li>287</li><li>288</li><li>289</li><li>290</li><li>291</li><li>292</li><li>293</li><li>294</li><li>295</li><li>296</li><li>297</li><li>298</li><li>299</li><li>300</li><li>301</li><li>302</li><li>303</li><li>304</li><li>305</li><li>306</li><li>307</li></ul>

  先梳理一下流程。首先是绘制,在dispatchDraw()方法中的代码如下:

<code class="hljs java has-numbering">    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dispatchDraw</span>(Canvas canvas)
    {
        <span class="hljs-keyword">super</span>.dispatchDraw(canvas);
        <span class="hljs-keyword">if</span> (!hasinit)
        {
            <span class="hljs-comment">//暂时写死,应该通过XML设置</span>
            sidePadding = <span class="hljs-number">40</span>;
            topBottomPadding = <span class="hljs-number">40</span>;
            initPoints();
            resetFinished = <span class="hljs-keyword">true</span>;
        }

        drawCircle(canvas);
        drawLine(canvas);
    }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>

  首先先绘制布局中的其他控件,它们与图案锁没有任何关系。接下来分为3步:

  1、初始化。参见initPoints()方法,其作用为创建九个PatternPoint对象,并确定每一个圆的位置和密码。我们之前说视为这九个圆位于3*3的方格子中,不过这3*3的方格子不一定要紧贴着布局的边界,因此定义了两个变量sidePadding和topBottomPadding,用于记录方格子与布局边界之间的距离。不过我这里图省事儿直接将这两个值写死了,实际上最妥当的方案是在attrs.xml中定义这两个属性,然后在布局xml中定义这两个属性的值,最后在源文件中获取这两个属性,并且将它们的值赋值给变量。此外需要注意的是,初始化代码只需执行一次就够了,而dispatchDraw()会反复调用,因此需要一个控制变量记录初始化是否完毕。

  2、画圆。这个比较简单,根据不同圆当前处于的状态进行绘制即可。参见drawCircle()和getCirclePaint()方法。

  3、画线。这是最复杂的一部分,实现部分在drawLine()方法中,首先我们需要知道要画的是哪个颜色的线。从上面的效果展示可知,线的颜色一共分为两种:正在连线时和连线正确时是同一种颜色,另外就是连线错误时的颜色。这里需要使用一个变量记录当前是否处于连线错误状态,并且根据这个变量的值去获取不同的画笔(Paint对象)。

  前面说过,连线分为两部分,一部分是点和点之间的连线(我们称之为连接线),另一部分是最后一个点和当前手指的位置的连线(我们称之为自由线)。无论是连接线还是自由线,都需要知道我之前所有连接过的点的顺序,因此需要一个ArrayList来记录它。在绘制自由线的时候,需要知道当前手指的位置(X,Y坐标),这两个值是在onTouchEvent()中获取的,因此需要两个类变量记录它。此外,当我的手抬起来之后,表示我的一次连线已经结束了,这时是不需要绘制自由线的,因此这里要额外加一个判断。



  接下来分析一下触摸事件,它的设计思路大致如下:

  1、在按下时,如果我手指的位置正处于某个点中,那么一次连线开始,并且把这个点加入到选中点的List中,作为第一个点。

  2、在移动时,如果我已经开始连线,那么需要明确的是我的选中列中至少已经有一个点了(至少会有一个起始点)。此时需要判断是否经过了某一个点,并且这个点是还没有进入选中列中的点。在满足这些条件之后,进行下面判断:

   a)查看我上一个连接的点和这次经过的点中间是否需要插入点(比如上一个点是左上角的点,这里经过的点是右上角的点,并且正上方的点还没有进入选中列,此时,应当将正上方的点加入到选中列中,并且在右上角这个点之前插入)

   b)增加这个经过的点到选中列中。

  3、在抬起时,如果我已经开始连线,表明我这次连线结束了。这时如果存在连接线而不是仅仅有自由线(即选中列中的点至少有两个),则去计算这个图案对应的密码,提供给外部进行密码长度和密码正误的判断。既然说到要给外部进行回调,因此需要提供一个接口。

  4、在每当发生触摸事件之后,都重新绘制连线。



  下面强调几个特殊的方法。

  1、insertPointIfNeeds(),这个方法用于上面说的触摸事件中2a这个步骤,判断两个点中间是否需要插入额外的一个点到选中队列中。我在程序里把9个点从左到右,从上到下分别标为1-9。那么1和3中需要插入2,4和6中需要插入5等等这些判断,我通过一个常量矩阵进行获取,这样就避免了大片的if,else。矩阵中的值表示需要插入点的index值,-1表示没有。当然有这样的点不一定就表示需要插入到选中列中,还需要满足当前经过的点和中间插入的点之前都没有在选中列中的条件。

  2、setAllSelectedPointsError(),这个方法提供给外部Activity调用,当用户判断出图案密码太短或者图案密码错误时,将所有选中列中的点的状态设为错误状态,同时,将连线的颜色设为错误时连线的颜色。注意设置完成之后需要重绘。

  3、processFinish(),这个方法主要说一下返回值,从程序中可以看出,它的返回值是一个时间值。因为当用户连线完成之后,无论其连线正确与否,都需要将这个连线图案保持一段时间,而并不是瞬间就恢复到初始状态。

  4、reset()方法和resetFinished变量,reset()的作用是将所有记录状态的值都恢复到初始化完成的状态,随后将resetFinished置为true。而在resetFinished为false时,按下、移动、抬起这些触摸事件都是不起作用的。之前说过,当用户连线完成之后,需要保持图案一定时间,而这段时间之内,是不允许用户进行连线的,resetFinished变量的作用就是控制这个部分。reset()方法中,当所有变量都重置之后,又给外部提供了一个回调方法,它的作用是告诉Activity已经重置完成,如果Activity中有关于密码正误判断的显示,则可在这个回调中进行重置。



  最后附带上这个扩展的RelativeLayout的使用,即Activity和对应的xml布局中的代码,这部分很容易理解,就不解释了。

<code class="hljs avrasm has-numbering"><<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.liusiqian</span><span class="hljs-preprocessor">.patternlock</span><span class="hljs-preprocessor">.PatternLockLayout</span>
    xmlns:android=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
    android:id=<span class="hljs-string">"@+id/layout_lock"</span>
    android:layout_width=<span class="hljs-string">"match_parent"</span>
    android:layout_height=<span class="hljs-string">"match_parent"</span>>

    <TextView
        android:id=<span class="hljs-string">"@+id/txt_patternlock_info"</span>
        android:layout_width=<span class="hljs-string">"wrap_content"</span>
        android:layout_height=<span class="hljs-string">"wrap_content"</span>
        android:layout_centerHorizontal=<span class="hljs-string">"true"</span>
        android:text=<span class="hljs-string">"信息"</span>
        android:textSize=<span class="hljs-string">"28sp"</span>
        android:layout_marginTop=<span class="hljs-string">"60dp"</span>/>

</<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.liusiqian</span><span class="hljs-preprocessor">.patternlock</span><span class="hljs-preprocessor">.PatternLockLayout</span>></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
<code class="hljs java has-numbering"><span class="hljs-keyword">package</span> com.liusiqian.patternlock;

<span class="hljs-keyword">import</span> android.app.Activity;
<span class="hljs-keyword">import</span> android.os.Bundle;
<span class="hljs-keyword">import</span> android.widget.TextView;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Activity</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">PatternLockLayout</span>.<span class="hljs-title">OnPatternStateListener</span>
{</span>
    <span class="hljs-keyword">private</span> TextView tvInfo;
    <span class="hljs-keyword">private</span> PatternLockLayout lockLayout;

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState)
    {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tvInfo = (TextView) findViewById(R.id.txt_patternlock_info);
        tvInfo.setText(<span class="hljs-string">"请绘制图案密码"</span>);
        lockLayout = (PatternLockLayout) findViewById(R.id.layout_lock);
        lockLayout.setOnPatternStateListener(<span class="hljs-keyword">this</span>);
    }

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onFinish</span>(String password, <span class="hljs-keyword">int</span> sizeOfPoints)
    {
        <span class="hljs-keyword">if</span>(sizeOfPoints<<span class="hljs-number">5</span>)
        {
            tvInfo.setText(<span class="hljs-string">"请连接至少5个点"</span>);
            lockLayout.setAllSelectedPointsError();
        }
        <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>( !password.equals(<span class="hljs-string">"1235789"</span>) )
        {
            tvInfo.setText(<span class="hljs-string">"图案密码错误"</span>);
            lockLayout.setAllSelectedPointsError();
        }
        <span class="hljs-keyword">else</span>
        {
            tvInfo.setText(<span class="hljs-string">"图案正确"</span>);
        }
    }

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onReset</span>()
    {
        tvInfo.setText(<span class="hljs-string">"请绘制图案密码"</span>);
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li></ul>

  最后还是要重申一下,这个程序只是阐述了图案锁的核心功能,本身并不完美。很多写死在程序里的变量甚至是常量实际上都可以定义成属性写在xml文件里,然后在layout中配置,这样能使得程序的可扩展性达到一个更高的层次,使用起来更加自如。

  原谅我犯懒,只做到这里了~

时间: 2024-10-13 10:47:38

Android中图案锁的实现的相关文章

Android中应用锁的实现之账号盗取

一.前言 前几天忙着公司的活,最近又可以歇歇了,休息不能不做事呀?今天就来研究一下Android中应用锁的实现.应用锁顾名思义就是对app进行加密,在打开app的时候需要输入指定的密码才能打开应用. 现在市场中这种应用很多的,他们的实现原理很简单,网上也有人解释了. 二.市场中应用锁apk的分析 我们来随便看一下那些加密锁的应用的实现,这里我从豌豆荚上面下载了一个:应用锁.apk 安装运行,然后对360手机卫士进行加密, 我们在打开360手机卫士: 这时候就弹出了加密的页面 这时候我们查看一下系

Android中图案解锁的设计原理和实现过程

Android中图案解锁 首先要理解图案的实现原理,上一张图: 由上图,可以看出,图案中手势的记录是1-9或0-8的,保存的顺序就是密码,当然有些是可以重复的,为了安全,肯定不能直接存原顺序,一定是要加密处理的,如MD5或Hash散列. (作者: a day a better) 图案解锁中自定义View,是其中最为关键的一部分.下面是自定义LockView的实现,里面的注释写的很详细了. <span style="font-size:14px;">package com.e

android中键盘锁的问题

android中经常使用KeyguardLock来进行解锁,但是使用后需要调用reenableKeyguard()将锁释放,否则的话会导致其它的进程无法锁住屏幕,同样使用WakeLock唤醒屏幕后也需要使用release()释放,否则会导致系统无法进入休眠.

Android中锁屏密码算法解析以及破解方案

一.前言 最近玩王者荣耀,下载了一个辅助样本,结果被锁机了,当然破解它很简单,这个后面会详细分析这个样本,但是因为这个样本引发出的欲望就是解析Android中锁屏密码算法,然后用一种高效的方式制作锁机恶意样本.现在的锁机样本原理强制性太过于复杂,没意义.所以本文就先来介绍一下android中的锁屏密码算法原理. 二.锁屏密码方式 我们知道Android中现结单支持的锁屏密码主要有两种: 一种是手势密码,也就是我们常见的九宫格密码图 一种是输入密码,这个也分为PIN密码和复杂字符密码,而PIN密码

Android中使用SurfaceView和Canvas来绘制动画

其实每个View中都有Canvas可以用来绘制动画,只需要在这个View中重载onDraw()方法就可以,但是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做"画布")就和HTML5中的canvas标签一样可以在一定区域内自由绘制图形.Canvas+SurfaceView制作的动画与View Animation和Property Animation这类动画比起来更加适合大量的集中播放的动画,比如游戏画面.相机的图像显示等. 因为SurfaceView通常会在

Android基础入门教程——8.1.2 Android中的13种Drawable小结 Part 2

Android基础入门教程--8.1.2 Android中的13种Drawable小结 Part 2 标签(空格分隔): Android基础入门教程 本节引言: 本节我们继续来学习Android中的Drawable资源,上一节我们学习了: ColorDrawable:NinePatchDrawable: ShapeDrawable:GradientDrawable!这四个Drawable~ 而本节我们继续来学习接下来的五个Drawable,他们分别是: BitmapDrawable:Insert

Android中微信抢红包插件原理解析和开发实现

一.前言 自从去年中微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导致了.或许是网络的原因,而且这个也是最大的原因.但是其他的不可忽略的因素也是要考虑到进去的,比如在手机充电锁屏的时候,我们并不知道有人已经开始发红包了,那么这时候也是让我们丧失了一大批红包的原因.那么关于网络的问题,我们开发者可能用相关技术无法解决(当然在Google和Facebook看来的话,他们

Android中的单例模式

定义: 单例模式:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 使用场景: 确保某一个类有且只有一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个. UML类图: 单例模式几个关键点: 1.构造函数不对外开放,一般为private. 2.通过一个静态方法或者枚举返回单例类对象. 3.确保单例类的对象有且只有一个,尤其在多线程环境下. 4.确保单例类对象在反序列化时不会重新构建对象. 单例模式简单代码: public class Single

Android中Canvas绘图之Shader使用图文详解

概述 我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader,这样就可以绘制出多彩的图形.那么Shader是什么呢?做过GPU绘图的同学应该都知道这个词汇,Shader就是着色器的意思.我们可以这样理解,Canvas中的各种drawXXX方法定义了图形的形状,画笔中的Shader则定义了图形的着色.外观,二者结合到一起就决定了最终Canvas绘制的被色彩填充的图形的样子. 类android.graphics