parent
df78c21640
commit
a6feecbe39
@ -0,0 +1,264 @@
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 手势锁自定义视图
|
||||
*/
|
||||
public class GestureLockView extends View {
|
||||
private static final int MATRIX_SIZE = 3; // 3x3矩阵
|
||||
|
||||
private Paint mPaint; // 画笔
|
||||
private List<GesturePoint> mPoints; // 手势点集合
|
||||
private List<Integer> mSelectedPoints; // 已选择的点集合
|
||||
private List<GestureLine> mLines; // 连接线集合
|
||||
private GesturePoint mCurrentPoint; // 当前手指位置点
|
||||
private boolean mIsDrawing; // 是否正在绘制
|
||||
|
||||
private OnGestureCompleteListener mListener; // 手势完成监听器
|
||||
|
||||
public interface OnGestureCompleteListener {
|
||||
void onGestureComplete(List<Integer> selectedPoints);
|
||||
}
|
||||
|
||||
public static class GesturePoint {
|
||||
public float x; // X坐标
|
||||
public float y; // Y坐标
|
||||
public int index; // 点的索引 (0-8)
|
||||
public boolean isSelected; // 是否被选中
|
||||
|
||||
public GesturePoint(float x, float y, int index) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.index = index;
|
||||
this.isSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GestureLine {
|
||||
public GesturePoint startPoint; // 起始点
|
||||
public GesturePoint endPoint; // 结束点
|
||||
|
||||
public GestureLine(GesturePoint start, GesturePoint end) {
|
||||
this.startPoint = start;
|
||||
this.endPoint = end;
|
||||
}
|
||||
}
|
||||
|
||||
public GestureLockView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public GestureLockView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public GestureLockView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mPaint = new Paint();
|
||||
mPaint.setAntiAlias(true); // 抗锯齿
|
||||
mPaint.setStrokeWidth(4); // 线宽
|
||||
|
||||
mPoints = new ArrayList<>();
|
||||
mSelectedPoints = new ArrayList<>();
|
||||
mLines = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
|
||||
// 计算点的位置
|
||||
int padding = Math.min(w, h) / 10; // 边距
|
||||
int cellWidth = (w - 2 * padding) / (MATRIX_SIZE - 1); // 每个格子的宽度
|
||||
int cellHeight = (h - 2 * padding) / (MATRIX_SIZE - 1); // 每个格子的高度
|
||||
|
||||
mPoints.clear();
|
||||
for (int i = 0; i < MATRIX_SIZE; i++) {
|
||||
for (int j = 0; j < MATRIX_SIZE; j++) {
|
||||
float x = padding + j * cellWidth;
|
||||
float y = padding + i * cellHeight;
|
||||
mPoints.add(new GesturePoint(x, y, i * MATRIX_SIZE + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
// 绘制所有点
|
||||
for (GesturePoint point : mPoints) {
|
||||
drawPoint(canvas, point);
|
||||
}
|
||||
|
||||
// 绘制连接线
|
||||
for (GestureLine line : mLines) {
|
||||
drawLine(canvas, line);
|
||||
}
|
||||
|
||||
// 如果正在绘制,绘制从最后一点到当前手指位置的连线
|
||||
if (mIsDrawing && mCurrentPoint != null && !mSelectedPoints.isEmpty()) {
|
||||
GesturePoint lastPoint = mPoints.get(mSelectedPoints.get(mSelectedPoints.size() - 1));
|
||||
mPaint.setColor(Color.parseColor("#FFA500")); // 橙色
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
canvas.drawLine(lastPoint.x, lastPoint.y, mCurrentPoint.x, mCurrentPoint.y, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawPoint(Canvas canvas, GesturePoint point) {
|
||||
float radius = Math.min(getWidth(), getHeight()) / 15f; // 点的半径
|
||||
|
||||
if (point.isSelected) {
|
||||
// 绘制选中的点(大圆圈)
|
||||
mPaint.setColor(Color.parseColor("#FFA500")); // 橙色
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawCircle(point.x, point.y, radius, mPaint);
|
||||
|
||||
// 绘制内部小圆点
|
||||
mPaint.setColor(Color.WHITE);
|
||||
canvas.drawCircle(point.x, point.y, radius / 2, mPaint);
|
||||
} else {
|
||||
// 绘制未选中的点(圆环)
|
||||
mPaint.setColor(Color.GRAY);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(4);
|
||||
canvas.drawCircle(point.x, point.y, radius, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawLine(Canvas canvas, GestureLine line) {
|
||||
mPaint.setColor(Color.parseColor("#FFA500")); // 橙色
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(8);
|
||||
canvas.drawLine(line.startPoint.x, line.startPoint.y,
|
||||
line.endPoint.x, line.endPoint.y, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
handleTouchDown(x, y);
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
handleTouchMove(x, y);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
handleTouchUp();
|
||||
break;
|
||||
}
|
||||
|
||||
invalidate(); // 重绘
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleTouchDown(float x, float y) {
|
||||
mSelectedPoints.clear();
|
||||
mLines.clear();
|
||||
mIsDrawing = true;
|
||||
|
||||
// 检查是否点击了某个点
|
||||
for (GesturePoint point : mPoints) {
|
||||
float distance = (float) Math.sqrt(Math.pow(x - point.x, 2) + Math.pow(y - point.y, 2));
|
||||
if (distance < Math.min(getWidth(), getHeight()) / 10f) { // 如果在点的范围内
|
||||
selectPoint(point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTouchMove(float x, float y) {
|
||||
if (!mIsDrawing) return;
|
||||
|
||||
// 更新当前手指位置
|
||||
mCurrentPoint = new GesturePoint(x, y, -1);
|
||||
|
||||
// 检查是否有新的点被经过
|
||||
for (GesturePoint point : mPoints) {
|
||||
if (point.isSelected) continue; // 已经选过的点不再处理
|
||||
|
||||
float distance = (float) Math.sqrt(Math.pow(x - point.x, 2) + Math.pow(y - point.y, 2));
|
||||
if (distance < Math.min(getWidth(), getHeight()) / 10f) { // 如果在点的范围内
|
||||
selectPoint(point);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTouchUp() {
|
||||
if (!mIsDrawing) return;
|
||||
|
||||
mIsDrawing = false;
|
||||
mCurrentPoint = null;
|
||||
|
||||
// 通知手势完成
|
||||
if (mListener != null && !mSelectedPoints.isEmpty()) {
|
||||
mListener.onGestureComplete(mSelectedPoints);
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
reset();
|
||||
}
|
||||
|
||||
private void selectPoint(GesturePoint point) {
|
||||
if (!point.isSelected) {
|
||||
point.isSelected = true;
|
||||
mSelectedPoints.add(point.index);
|
||||
|
||||
// 添加连接线(如果不是第一个点)
|
||||
if (mSelectedPoints.size() > 1) {
|
||||
int lastIndex = mSelectedPoints.get(mSelectedPoints.size() - 2);
|
||||
GesturePoint lastPoint = mPoints.get(lastIndex);
|
||||
mLines.add(new GestureLine(lastPoint, point));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
for (GesturePoint point : mPoints) {
|
||||
point.isSelected = false;
|
||||
}
|
||||
mSelectedPoints.clear();
|
||||
mLines.clear();
|
||||
mCurrentPoint = null;
|
||||
}
|
||||
|
||||
public void setOnGestureCompleteListener(OnGestureCompleteListener listener) {
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除当前手势并重置视图
|
||||
*/
|
||||
public void clearGesture() {
|
||||
reset();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前手势点的数量
|
||||
*/
|
||||
public int getSelectedPointsCount() {
|
||||
return mSelectedPoints.size();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue