Android自定義控制元件系列之:鎖屏頁
介紹
- 翻閱以前寫過的demo,發現在1.52225年前擼過一個仿鎖屏功能的自定義View,特此記錄。
基本思路
- 分析一下,android鎖屏一般為九宮格,將螢幕九等分,以每部分的中點為圓心畫圓,每個圓有預設狀態和連線狀態以及錯誤狀態,根據觸控區域判斷觸控的點,在onDraw裡畫出點和線,在需要的地方設定Paint的顏色等屬性後postInvalidate一下,這樣來實現點的不同狀態的顯示。每連線一個點都將此點的下標存入陣列,可在activity設定開鎖密碼,連線完後判斷是否正確。
程式碼實現
給這個view起個低調且奢華的名字,繼承View,然後開擼。
特別注意:名字不屌,View寫不好。:happy:
- 計算9個點的座標
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//鎖屏3x3點矩陣
widthArea = width / 3;
heightArea = height / 3;
CIRCLE_RADIUS = widthArea / 4;//設定半徑
//根據螢幕設定9個座標點
a[0][0] = widthArea / 2;
a[1][0] = widthArea * 2 * 0.75f;
a[2][0] = widthArea * 3 * 5 / 6;
a[3][0] = widthArea / 2;
a[4][0] = widthArea * 2 * 0.75f;
a[5][0] = widthArea * 3 * 5 / 6;
a[6][0] = widthArea / 2;
a[7][0] = widthArea * 2 * 0.75f;
a[8][0] = widthArea * 3 * 5 / 6;
a[0][1] = heightArea / 2;
a[1][1] = heightArea / 2;
a[2][1] = heightArea / 2;
a[3][1] = heightArea * 2 * 0.75f;
a[4][1] = heightArea * 2 * 0.75f;
a[5][1] = heightArea * 2 * 0.75f;
a[6][1] = heightArea * 3 * 5 / 6;
a[7][1] = heightArea * 3 * 5 / 6;
a[8][1] = heightArea * 3 * 5 / 6;複製程式碼
- onDraw方法
protected void onDraw(Canvas canvas) {
//畫出已連線的點
for (int i = 0; i < positionArr.size(); i++) {
if (curCircle.contains(i)) {
canvas.drawCircle(positionArr.get(i).x, positionArr.get(i).y, CIRCLE_RADIUS, mClickPaint);
} else {
canvas.drawCircle(positionArr.get(i).x, positionArr.get(i).y, CIRCLE_RADIUS, mPaint);
}
}
//已連線的點之間的線
for (int i = 0; i < curCircle.size(); i++) {
if (i + 1 < curCircle.size()) {
canvas.drawLine(positionArr.get(curCircle.get(i)).x, positionArr.get(curCircle.get(i)).y, positionArr.get(curCircle.get(i + 1)).x, positionArr.get(curCircle.get(i + 1)).y, mLinePaint);
}
}
//最後的點與觸控位置之間的線
if (moveX != 0 && moveY != 0 && curCircle.size() > 0 && curCircle.size() < 9 && isTouch) {
canvas.drawLine(positionArr.get(curCircle.get(curCircle.size() - 1)).x, positionArr.get(curCircle.get(curCircle.size() - 1)).y, moveX, moveY, mLinePaint);
}
}複製程式碼
- onTouchEvent方法
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
checkPassword();
break;
case MotionEvent.ACTION_MOVE:
moveX = event.getX();
moveY = event.getY();
//判斷觸控點下標
int pos = whichCircle(event.getX(), event.getY());
//存入陣列
if (pos != -1 && !curCircle.contains(pos)) {
curCircle.add(pos);
System.out.println(pos);
}
postInvalidate();
break;
}
return true;
}複製程式碼
- 判斷觸控點
private int whichCircle(float x, float y) {
int position = -1;
for (int i = 0; i < positionArr.size(); i++) {
if (Math.abs(x - positionArr.get(i).x)
< CIRCLE_RADIUS && Math.abs(y - positionArr.get(i).y) <CIRCLE_RADIUS) {
position = i;
}
}
return position;
}複製程式碼
- 根據已連線的陣列去判斷密碼是否正確,然後回撥
private void checkPassword() {
StringBuilder pwd = new StringBuilder();
for (Integer pos : curCircle) {
pwd.append(pos).append("");
}
//連線點數小於等於2則忽略此次連線
if (curCircle.size() > 2) {
listener.checkListener(pwd.toString());
if (!password.equals(pwd.toString())) {
mLinePaint.setColor(Color.RED);
mClickPaint.setColor(Color.RED);
postInvalidate();
isTouch = false;
postDelayed(new Runnable() {
@Override
public void run() {
reset();
}
}, 1000);
}
} else {
//重置View
reset();
}
}複製程式碼
原始碼地址
控制元件:t.cn/Rp4UZHK 原始碼附有註釋
用法:t.cn/Rp4b4OV
最終效果
最後祝看過的人進步~