Android中图案锁的实现
Posted Manaasdfasdf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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()中获取的,因此需要两个类变量记录它。此外,当我的手抬起来之后,表示我的一次连线已经结束了,这时是不需要绘制自由线的
以上是关于Android中图案锁的实现的主要内容,如果未能解决你的问题,请参考以下文章
我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情