這篇文章主要介紹Android怎么實現九宮格解鎖,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
首先理清一下邏輯,我們要做NxN的九宮格 下圖是3x3的簡單圖例
// -(--)-(--)-(--)-
// -(--)-(--)-(--)-
// -(--)-(--)-(--)-

我們就把九宮格分解成
外圓 、內圓、連線三部分
外圓半徑Radius,內圓半徑dp(5)
建立一個集合來放置 外圓的圓心( 內圓的圓心也一樣)
private ArrayList<Point> mListCircle;//外圓的圓心
for (int i = 0; i < mCount; i++) {
for (int j = 0; j < mCount; j++) {
Point point = new Point((3 * i + 2) * (int) mRadius, (3 * j + 2) * (int) mRadius);
mListCircle.add(point);
}
}這樣我們就初始化好了內外圓的位置point集合
我們draw一下看一下效果
void drawAll_Cicle(Canvas canvas) {
for (int i = 0; i < mListCircle.size(); i++) {
Point point = mListCircle.get(i);
canvas.drawCircle(point.x, point.y, mRadius, mPaint);
canvas.drawCircle(point.x, point.y, mMinRadius, miniPaint);
}效果圖就是上圖了 (哈哈一樣的)
主結構已經畫完了,接下來就是如何繪制點與點之間的連線了,有人會覺得沒思路,其實很簡單了,以3X3 為例子哈
我們可以給這九個棋子編號1--9號,把他存入LinkedHashSet中,著重介紹這個LinkedHashSet有順序不重復這個真的在合適不過了。
這樣就不會有重復的事情了。這個和解鎖時候的密碼也很契合。所以選對了存儲方式會事半功倍。
還有一個問題,就是點擊邊界問題,這個好解決,我們把每一個棋子都花矩形,通過圓來控制邊界,(其實也可以通過矩形來控制邊界,這個也很簡單,原理是差不多的,有興趣的同學可以下去試試)
同樣也是用集合。和上邊的圓是一樣一樣的。
ArrayList<RectF> mListRectFs;
for (int i = 0; i < mCount; i++) {
for (int j = 0; j < mCount; j++) {
RectF rectF = new RectF((3 * i + 1) * mRadius, (3 * j + 1) * mRadius, (3 * i + 3) * mRadius, (3 * j + 3) * mRadius);
mListRectFs.add(rectF);
}
}好邊界也有了,我們來計算邊界返回編號
/**
* 點和圓形碰撞檢測
*
* @param x1 手指接觸點
* @param y1 手指接觸點
* @param x2 外圓
* @param y2 外圓
* @param radius 半徑
* @return
*/
private boolean isCollision(float x1, float y1, float x2, float y2, float radius) {
if (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= radius) {
// 如果點和圓心距離小于或等于半徑則認為發生碰撞
return true;
}
return false;
}
/**
* 判斷觸摸點在哪個item上
*
* @param x
* @param y
* @return
*/
private int touchIndex(float x, float y) {
for (int i = 0; i < mListCircle.size(); i++) {
Point p = mListCircle.get(i);
if (isCollision(x, y, p.x, p.y, mRadius)) {
return i;
}
}
return -1;
}幾個關鍵點都寫到了接下來就是具體的細節了。我把代碼都貼上來,注釋的很詳細。當然加入了一個手指觸控點,更加好看一些。
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
/**
* Created by ld on 2017/7/25.
*/
public class NineGridLockView extends View {
private Context context;
int index_point = 0;
private float mDensity;
private int mCount = 3;
private ArrayList<RectF> mListRectFs;//圓的外形矩形
private ArrayList<Point> mListCircle;//外圓的圓心
private LinkedHashSet<Integer> mSetPoints;//記錄需要連線的外圓圓心點在mListCircle中的索引值,LinkedHashSet線性不可重復 集合,FIFO
private Paint mPaint, miniPaint;//畫筆
private float mRadius;//外圓半徑
private float mMinRadius;//內圓半徑
private float mStrokeWidth = 10; //繪制時的畫筆寬度
private Point mMovePoint; //記錄手指移動時的點
public NineGridLockView(Context context) {
this(context, null);
}
public NineGridLockView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
mDensity = getContext().getResources().getDisplayMetrics().density;
mListRectFs = new ArrayList<>();
mListCircle = new ArrayList<>();
mPaint = new Paint();
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLUE);
miniPaint = new Paint();
miniPaint.setColor(Color.BLACK);
miniPaint.setAntiAlias(true);
miniPaint.setStyle(Paint.Style.STROKE);
miniPaint.setStrokeWidth(5);
mMinRadius = dp(5);
mSetPoints = new LinkedHashSet<>();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawAll_Cicle(canvas);
draw_line(canvas);
}
private int dp(int dp) {
return (int) (dp * mDensity + 0.5f);
}
//繪制 連接線
void draw_line(Canvas canvas) {
Point p1 = null;
Point p2 = null;
//從結合中獲取 move過的點
for (int index : mSetPoints) {
//當第一個點為null的時候 給第一個點賦值
if (p1 == null) {
p1 = mListCircle.get(index);
//然后 給第二個點賦值 兩點一條線
} else if (p2 == null) {
p2 = mListCircle.get(index);
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);
//p1 挪到p2
p1 = p2;
//接下來就是第三個點了 乃至更多點
} else {
//p2重新賦值 兩點一條線
p2 = mListCircle.get(index);
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);
//p1 挪到p2
p1 = p2;
}
}
//繪制實時連線
if (mMovePoint != null && p1 != null) {
canvas.drawLine(p1.x, p1.y, mMovePoint.x, mMovePoint.y, mPaint);
}
}
//繪制 外圓 內圓
void drawAll_Cicle(Canvas canvas) {
for (int i = 0; i < mListRectFs.size(); i++) {
Point point = mListCircle.get(i);
//如果move過的 就換顏色
if (mSetPoints.contains(i)) {
canvas.drawCircle(point.x, point.y, mRadius, miniPaint);
canvas.drawCircle(point.x, point.y, mMinRadius, mPaint);
} else {
canvas.drawCircle(point.x, point.y, mRadius, mPaint);
canvas.drawCircle(point.x, point.y, mMinRadius, miniPaint);
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
float w = Math.min(getMeasuredWidth(), getMeasuredHeight());
// -(--)-(--)-(--)-
// -(--)-(--)-(--)-
// -(--)-(--)-(--)-
mRadius = getMeasuredWidth() * 1.00f / (mCount * 3 + 1);
float rectWH = mRadius * 2;
mListRectFs.clear();
mListCircle.clear();
for (int i = 0; i < mCount; i++) {
for (int j = 0; j < mCount; j++) {
RectF rectF = new RectF((3 * i + 1) * mRadius, (3 * j + 1) * mRadius, (3 * i + 3) * mRadius, (3 * j + 3) * mRadius);
mListRectFs.add(rectF);
Point point = new Point((3 * i + 2) * (int) mRadius, (3 * j + 2) * (int) mRadius);
mListCircle.add(point);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float point_x = event.getX();
float point_y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
mMovePoint = null;
mSetPoints.clear();
invalidate();
break;
case MotionEvent.ACTION_MOVE:
int index = touchIndex(point_x, point_y);
if (mMovePoint == null) {
mMovePoint = new Point((int) point_x, (int) point_y);
} else {
mMovePoint.set((int) point_x, (int) point_y);
}
if (index != -1) {
mSetPoints.add(index);
if (index_point != mSetPoints.size()) {
index_point = mSetPoints.size();
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
}
}
invalidate();
break;
}
return true;
}
/**
* 判斷觸摸點在哪個item上
*
* @param x
* @param y
* @return
*/
private int touchIndex(float x, float y) {
for (int i = 0; i < mListCircle.size(); i++) {
Point p = mListCircle.get(i);
if (isCollision(x, y, p.x, p.y, mRadius)) {
return i;
}
}
return -1;
}
/**
* 點和圓形碰撞檢測
*
* @param x1 手指接觸點
* @param y1 手指接觸點
* @param x2 外圓
* @param y2 外圓
* @param radius 半徑
* @return
*/
private boolean isCollision(float x1, float y1, float x2, float y2, float radius) {
if (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= radius) {
// 如果點和圓心距離小于或等于半徑則認為發生碰撞
return true;
}
return false;
}
}以上是“Android怎么實現九宮格解鎖”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。