Android自定义九宫格手势解锁组件
項目來源
別的不說,先看一下效果圖:
九宮格手勢圖案解鎖功能在很多應用中都在使用,本文介紹的組件來自于開源項目PatternLocker的翻寫,原工程是使用Kotlin開發的,由于我們項目是使用java開發,所以將原工程使用Java進行了翻寫,如果需要kotlin版本的請移步原工程Kotlin版九宮格手勢解鎖組件,如果需要Java版本的可以點此下載Java版九宮格手勢解鎖組件。本文主要介紹Java版本九宮格手勢解鎖組件的使用和實現原理。
支持功能
- 支持自定義各狀態下(未操作時、操作時以及操作出錯時)線顏色、填充色和線寬;
- 支持自定義各種狀態下(未操作時、操作時以及操作出錯時)每個CellView樣式和連接線樣式;
- 支持設置圖案繪制完成后延遲自動清除的時長(默認1秒);
- 支持是否跳過中間點(默認不跳過);
- 支持是否觸碰震動反饋(默認不震動);
- 支持指示器輔助控件可選擇使用;
- 業務邏輯(至少連點幾個點、驗證時最多可出錯幾次等)須自定義
九宮格實現原理
1、九宮格由9個格子組成,首先給每個格子分配id,9個cell的編號如下:
0 1 2
3 4 5
6 7 8
2、給每個格子設置坐標
x 表示該cell的x坐標(點坐標)
y 表示該cell的y坐標(點坐標)
九宮格每個格子x,y 點坐標編號如下:
(0,0) (1,0) (2,0)
(0,1) (1,1) (2,1)
(0,2) (1,2) (2,2)
3、每個格子就是一個圓,所以需要圓心坐標和半徑,格子圓心之間距離為3個半徑,
centerX 表示該cell的圓心x坐標(相對坐標)
centerY 表示該cell的圓心y坐標(相對坐標)
centerX, centerY 圓心坐標如下:
(radius, radius) (4radius, radius) (7radius, radius)
(radius, 4radius) (4radius, 4radius) (7radius, 4radius)
(radius, 7radius) (4radius, 7radius) (7radius, 7radius)
4、每個格子需要標記是否被選中狀態
isHit 表示該cell是否被設置的標記
工程源碼介紹
采用自定義View的形式,組件分為兩部分,第一部分是指示器View,第二部分是九宮格繪制View。
指示器View:
九宮格View:
<com.github.gesture.lockview.PatternLockerViewandroid:id="@+id/patternLockerView"android:layout_width="250dp"android:layout_height="250dp" />這兩個view可以拆開使用,如果不需要指示器,就只集成九宮格View即可。由于指示器View和九宮格View邏輯差不多,這里只簡單分析一下九宮格View的實現代碼。
九宮格View相關類:
PatternLockerView:九宮格View實現類;
DefaultLockerNormalCellView:默認九宮格每一個格子實現類;
DefaultLockerLinkedLineView:默認九宮格連線實現類;
DefaultLockerHitCellView:默認九宮格選中后格子樣式實現類;
PatternLockerView
該類主要初始化九宮格9個格子實體,并且重寫onDraw和 onMeasure方法,
初始化init方法主要讀取attr中的配置屬性;
onMeasure方法中選擇寬和高的最小值設為View的寬高。
onDraw方法:
drawLinkedLine方法調用的是DefaultLockerLinkedLineView中畫線方法;
drawCells方法調用的是DefaultLockerNormalCellView中畫格子方法;
下面分別分析一下如何畫格子和畫連接線的。
DefaultLockerNormalCellView
畫格子方法如下,先畫個外圓,然后再畫個內圓。
public void draw(Canvas canvas, CellBean cellBean) {int saveCount = canvas.save();// draw outer circlethis.paint.setColor(this.styleDecorator.getNormalColor());canvas.drawCircle(cellBean.getCenterX(), cellBean.getCenterY(), cellBean.getRadius(), this.paint);// draw fill circlethis.paint.setColor(this.styleDecorator.getFillColor());canvas.drawCircle(cellBean.getCenterX(), cellBean.getCenterY(), cellBean.getRadius() - this.styleDecorator.getLineWidth(), this.paint);canvas.restoreToCount(saveCount);}DefaultLockerHitCellView
繪制選中的格子是先畫外圓,再畫填充圓,最后畫內圓,只是顏色不一樣。
@Overridepublic void draw(Canvas canvas, CellBean cellBean, boolean isError) {int saveCount = canvas.save();// draw outer circle 畫外圓this.paint.setColor(this.getColor(isError));canvas.drawCircle(cellBean.getCenterX(), cellBean.getCenterY(), cellBean.getRadius(), this.paint);// draw fill circle 畫填充圓this.paint.setColor(this.styleDecorator.getFillColor());canvas.drawCircle(cellBean.getCenterX(), cellBean.getCenterY(), cellBean.getRadius() - this.styleDecorator.getLineWidth(), this.paint);// draw inner circle 畫內部圓this.paint.setColor(this.getColor(isError));canvas.drawCircle(cellBean.getCenterX(), cellBean.getCenterY(), cellBean.getRadius() / 5f, this.paint);canvas.restoreToCount(saveCount);}DefaultLockerLinkedLineView
畫線方法有點復雜,是通過遍歷選中的格子id的集合,使用Path的moveTo移動線坐標,使用lineTo來連線,最后調用drawPath畫出線條。
public void draw(Canvas canvas, List<Integer> hitIndexList, List<CellBean> cellBeanList, float endX, float endY, boolean isError) {if (hitIndexList.isEmpty() || cellBeanList.isEmpty()) {return;}int saveCount = canvas.save();Path path = new Path();boolean first = true;for (int i = 0; i < hitIndexList.size(); i++) {// 記錄選中的點idInteger it = hitIndexList.get(i);if (0 <= it && it < cellBeanList.size()) {// 獲取選中的點CellBean c = cellBeanList.get(it);if (first) {path.reset();// 如果是第一個,則先將起點移動到第一個點path.moveTo(c.getCenterX(), c.getCenterY());first = false;} else {// 連接第一個點到第二個點path.lineTo(c.getCenterX(), c.getCenterY());}}}if ((endX != 0f || endY != 0f) && hitIndexList.size() < 9) {path.lineTo(endX, endY);}this.paint.setColor(this.getColor(isError));this.paint.setStrokeWidth(this.styleDecorator.getLineWidth());canvas.drawPath(path, this.paint);canvas.restoreToCount(saveCount);}onTouchEvent
主要邏輯實現在onTouchEvent方法中,分別處理手勢按下、滑動、抬起狀態時的邏輯。處理完邏輯都會調用重繪方法,然后觸發onDraw方法,再次執行繪制過程。
按下、滑動、抬起時都會調用updateHitState方法,在updateHitState方法中通過一個List集合來記錄被選中的格子的id,繪制的時候再根據該集合更新格子狀態。
文章只是粗略介紹一下九宮格手勢圖案解鎖組件的實現原理和過程,深入研究還需要把源碼下載下來看一下。
源碼下載:
Kotlin版九宮格手勢解鎖組件
Java版九宮格手勢解鎖組件
總結
以上是生活随笔為你收集整理的Android自定义九宫格手势解锁组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 慧眼识幸福
- 下一篇: Python实现九宫格解锁