안 드 로 이 드(Android)구 궁 격 잠 금 해제 쉽게 실현
15863 단어 android구 궁 격자 물 쇠 를 풀다
사고의 방향
먼저 우 리 는 구 궁 격 잠 금 해 제 를 실현 하 는 방향 을 분석 합 니 다.사용자 의 손가락 이 특정한 점 을 만 졌 을 때 이 점 이 구 궁 격 의 특정한 범위 안에 있 는 지,범위 안에 있 으 면 이 칸 은 선택 한 상태 가 됩 니 다.이후 사용자 의 손가락 이 미 끄 러 질 때 이 칸 의 원심 을 중심 으로 사용자 의 손가락 을 종점 으로 하고 두 점 을 연결한다.마지막 으로 사용자 가 손가락 을 들 었 을 때 그 어 진 구 궁 격 비밀번호 가 원래 의 비밀번호 와 일치 하 는 지 판단 합 니 다.
대체적인 사고방식 과 절 차 는 바로 위 와 같다.아래 에서 우 리 는 실천 해 볼 수 있다.
Point 클래스
우 리 는 먼저 Point 류 를 만들어 서 구 궁 격자 의 9 칸 을 표시 합 니 다.좌표 x,y 를 제외 하고 세 가지 모델 이 있 습 니 다.정상 모드,누 르 기 모드 와 오류 모드 입 니 다.패턴 에 따라 이 칸 의 색상 이 다 를 수 있 으 므 로 아래 에 설명 하 겠 습 니 다.
public class Point {
private float x;
private float y;
//
public static final int NORMAL_MODE = 1;
//
public static final int PRESSED_MODE = 2;
//
public static final int ERROR_MODE = 3;
private int state = NORMAL_MODE;
// , “1”、“2”
private String mark;
public String getMark() {
return mark;
}
public void setMark(String mark) {
this.mark = mark;
}
public Point(float x, float y, String mark) {
this.x = x;
this.y = y;
this.mark = mark;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
}
RotateDegrees 클래스위의 Point 클래스 가 있 으 면 우 리 는 Rotate Degrees 클래스 를 만들어 야 합 니 다.주요 역할 은 두 Point 좌표 간 의 각 도 를 계산 하 는 것 입 니 다.
public class RotateDegrees {
/**
* point
* @param a
* @param b
* @return
*/
public static float getDegrees(Point a, Point b) {
float degrees = 0;
float aX = a.getX();
float aY = a.getY();
float bX = b.getX();
float bY = b.getY();
if (aX == bX) {
if (aY < bY) {
degrees = 90;
} else {
degrees = 270;
}
} else if (bY == aY) {
if (aX < bX) {
degrees = 0;
} else {
degrees = 180;
}
} else {
if (aX > bX) {
if (aY > bY) { //
degrees = 180 + (float) (Math.atan2(aY - bY, aX - bX) * 180 / Math.PI);
} else { //
degrees = 180 - (float) (Math.atan2(bY - aY, aX - bX) * 180 / Math.PI);
}
} else {
if (aY > bY) { //
degrees = 360 - (float) (Math.atan2(aY - bY, bX - aX) * 180 / Math.PI);
} else { //
degrees = (float) (Math.atan2(bY - aY, bX - aX) * 180 / Math.PI);
}
}
}
return degrees;
}
/**
* point (x,y)
* @param a
* @param bX
* @param bY
* @return
*/
public static float getDegrees(Point a, float bX, float bY) {
Point b = new Point(bX, bY, null);
return getDegrees(a, b);
}
}
ScreenLockView 클래스그 다음 에 우 리 는 먼저 구 궁 격 에 관 한 몇 장의 사진 을 준비 해 야 한다.예 를 들 어 구 궁 격 의 칸 에서
NORMAL_MODE
모델 에서 파란색 이 고 손가락 에 눌 렸 을 때 구 궁 격 의 칸 은 녹색 이다.즉,위의 Point
가지 중 PRESSED_MODE
모델,그리고 ERROR_MODE
모델 에서 빨간색 이다.또한 도 트 사이 의 연결선 도 있 고 패턴 에 따라 색상 이 다 를 수 있 습 니 다.여기 서 나 는 그림 을 붙 이지 않 겠 다.그림 자원 이 생 긴 후에 우리 가 해 야 할 일 은 먼저 구조 기 에 그림 을 불 러 오 는 것 이다.
public class ScreenLockView extends View {
private static final String TAG = "ScreenLockView";
//
private Bitmap errorBitmap;
//
private Bitmap normalBitmap;
//
private Bitmap pressedBitmap;
//
private Bitmap lineErrorBitmap;
//
private Bitmap linePressedBitmap;
// ,
private int offset;
//
private boolean init;
//
private int radius;
//
private String password = "123456";
//
private Point[][] points = new Point[3][3];
private int width;
private int height;
private Matrix matrix = new Matrix();
private float moveX = -1;
private float moveY = -1;
//
private boolean isMove;
// , ,
private boolean isTouch = true;
//
private List<Point> pressedPoint = new ArrayList<>();
//
private OnScreenLockListener listener;
public ScreenLockView(Context context) {
this(context, null);
}
public ScreenLockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScreenLockView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
errorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_error);
normalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_normal);
pressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bitmap_pressed);
lineErrorBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_error);
linePressedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.line_pressed);
radius = normalBitmap.getWidth() / 2;
}
...
}
구조 기 에서 우 리 는 주로 그림 을 불 러 와 완성 하고 격자 의 반지름,즉 그림 너비 의 절반 을 얻 었 다.그리고
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
방법 을 살 펴 보 겠 습 니 다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthSize > heightSize) {
offset = (widthSize - heightSize) / 2;
} else {
offset = (heightSize - widthSize) / 2;
}
setMeasuredDimension(widthSize, heightSize);
}
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
방법 에서 주로 대응 하 는 편 이 량 을 얻어 아래 onDraw(Canvas canvas)
에서 구 궁 격 을 화면 중앙 에 그 릴 수 있 도록 한다.다음은
onDraw(Canvas canvas)
방법 입 니 다.
@Override
protected void onDraw(Canvas canvas) {
if (!init) {
width = getWidth();
height = getHeight();
initPoint();
init = true;
}
//
drawPoint(canvas);
if (moveX != -1 && moveY != -1) {
//
drawLine(canvas);
}
}
먼저 onDraw(Canvas canvas)
방법 을 첫 번 째 로 호출 할 지 여 부 를 판단 하고 첫 번 째 로 points 를 초기 화 합 니 다.
//
private void initPoint() {
points[0][0] = new Point(width / 4, offset + width / 4, "0");
points[0][1] = new Point(width / 2, offset + width / 4, "1");
points[0][2] = new Point(width * 3 / 4, offset + width / 4, "2");
points[1][0] = new Point(width / 4, offset + width / 2, "3");
points[1][1] = new Point(width / 2, offset + width / 2, "4");
points[1][2] = new Point(width * 3 / 4, offset + width / 2, "5");
points[2][0] = new Point(width / 4, offset + width * 3 / 4, "6");
points[2][1] = new Point(width / 2, offset + width * 3 / 4, "7");
points[2][2] = new Point(width * 3 / 4, offset + width * 3 / 4, "8");
}
initPoint()
방법 에서 주로 9 개의 칸 을 만 들 고 해당 하 는 위치 와 비밀 번 호 를 설정 했다.초기 화 완료 후 init 를 false 로 설정 하고 다음 에는 호출 하지 않 습 니 다.고 개 를 돌려
onDraw(Canvas canvas)
의 다른 논 리 를 살 펴 보고 drawPoint(canvas)
을 사용 하여 칸 을 그립 니 다.
//
private void drawPoint(Canvas canvas) {
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
int state = points[i][j].getState();
if (state == Point.NORMAL_MODE) {
canvas.drawBitmap(normalBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
} else if (state == Point.PRESSED_MODE) {
canvas.drawBitmap(pressedBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
} else {
canvas.drawBitmap(errorBitmap, points[i][j].getX() - radius, points[i][j].getY() - radius, null);
}
}
}
}
칸 을 그 리 는 것 은 매우 간단 하 다.주로 세 가지 로 나 뉜 다.일반 모드 에서 의 칸,모드 에서 의 칸 과 오류 모드 에서 의 칸 이다.onTouchEvent
칸 을 그린 후에 우 리 는 마지막
drawLine(canvas)
방법 을 보지 않 습 니 다.직선 을 그 리 는 것 은 사용자 손가락 의 터치 사건 과 밀접 한 관 계 를 가지 기 때문에 우 리 는 먼저 onTouchEvent(MotionEvent event)
방법 으로 눈 을 돌 립 니 다.
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isTouch) {
float x = event.getX();
float y = event.getY();
Point point;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//
point = isPoint(x, y);
if (point != null) {
point.setState(Point.PRESSED_MODE); //
pressedPoint.add(point);
}
break;
case MotionEvent.ACTION_MOVE:
if (pressedPoint.size() > 0) {
point = isPoint(x, y);
if (point != null) {
if (!crossPoint(point)) {
point.setState(Point.PRESSED_MODE);
pressedPoint.add(point);
}
}
moveX = x;
moveY = y;
isMove = true;
}
break;
case MotionEvent.ACTION_UP:
isMove = false;
String tempPwd = "";
for (Point p : pressedPoint) {
tempPwd += p.getMark();
}
if (listener != null) {
listener.getStringPassword(tempPwd);
}
if (tempPwd.equals(password)) {
if (listener != null) {
listener.isPassword(true);
}
} else {
for (Point p : pressedPoint) {
p.setState(Point.ERROR_MODE);
}
isTouch = false;
this.postDelayed(runnable, 1000);
if (listener != null) {
listener.isPassword(false);
}
}
break;
}
invalidate();
}
return true;
}
public interface OnScreenLockListener {
public void getStringPassword(String password);
public void isPassword(boolean flag);
}
public void setOnScreenLockListener(OnScreenLockListener listener) {
this.listener = listener;
}
MotionEvent.ACTION_DOWN
에서 먼저 isPoint(float x, float y)
방법 에서 사용자 가 사건 을 만 지 는 좌표 점 이 구 궁 격 의 임 의 한 칸 안에 있 는 지 판단 했다.그렇다면 이 9 궁 격 의 칸 을 pressedPoint
에 추가 해 야 합 니 다.
//
private Point isPoint(float x, float y) {
Point point;
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
point = points[i][j];
if (isContain(point, x, y)) {
return point;
}
}
}
return null;
}
// (x,y)
private boolean isContain(Point point, float x, float y) {
// (x,y)
return Math.sqrt(Math.pow(x - point.getX(), 2f) + Math.pow(y - point.getY(), 2f)) <= radius;
}
다음은 MotionEvent.ACTION_MOVE
의 논 리 를 봐 야 한다.처음에는 사용자 가 만 진 점 이 구 궁 격 의 어떤 칸 인지 판단 했다.그러나 MotionEvent.ACTION_DOWN
보다 한 단계 더 많 았 다.사용자 가 어떤 칸 을 만 졌 다 면 이 칸 이 pressedPoint
에 포함 되 었 는 지 판단 해 야 한다.
// pressedPoint
private boolean crossPoint(Point point) {
if (pressedPoint.contains(point)) {
return true;
}
return false;
}
마지막 으로 MotionEvent.ACTION_UP
을 살 펴 보고 pressedPoint
에 저 장 된 칸 을 옮 겨 다 니 며 사용자 가 그 은 비밀 번 호 를 얻 은 다음 에 미리 설정 한 비밀번호 와 비교 하면 OnScreenLockListene
r 모니터 를 되 돌려 줍 니 다.다 르 면 pressedPoint
의 모든 칸 모드 를 오류 모드 로 설정 하고 runnable
에서 reset()
을 호출 하여 pressedPoint
을 비우 고 보 기 를 다시 그리고 모니터 를 다시 조정 합 니 다.
private Runnable runnable = new Runnable() {
@Override
public void run() {
isTouch = true;
reset();
invalidate();
}
};
//
private void reset(){
for (int i = 0; i < points.length; i++) {
for (int j = 0; j < points[i].length; j++) {
points[i][j].setState(Point.NORMAL_MODE);
}
}
pressedPoint.clear();
}
지금 우 리 는 고 개 를 돌려 이전에 onDraw(Canvas canvas)
안에 있 었 던 drawLine(Canvas canvas)
방법 을 살 펴 보 자.
//
private void drawLine(Canvas canvas) {
// pressedPoint ,
for (int i = 0; i < pressedPoint.size() - 1; i++) {
//
Point point = pressedPoint.get(i);
//
Point nextPoint = pressedPoint.get(i + 1);
//
canvas.rotate(RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());
matrix.reset();
//
matrix.setScale(getDistance(point, nextPoint) / linePressedBitmap.getWidth(), 1f);
//
matrix.postTranslate(point.getX(), point.getY() - linePressedBitmap.getWidth() / 2);
if (point.getState() == Point.PRESSED_MODE) {
canvas.drawBitmap(linePressedBitmap, matrix, null);
} else {
canvas.drawBitmap(lineErrorBitmap, matrix, null);
}
//
canvas.rotate(-RotateDegrees.getDegrees(point, nextPoint), point.getX(), point.getY());
}
//
if (isMove) {
Point lastPoint = pressedPoint.get(pressedPoint.size() - 1);
canvas.rotate(RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());
matrix.reset();
Log.i(TAG, "the distance : " + getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth());
matrix.setScale(getDistance(lastPoint, moveX, moveY) / linePressedBitmap.getWidth(), 1f);
matrix.postTranslate(lastPoint.getX(), lastPoint.getY() - linePressedBitmap.getWidth() / 2);
canvas.drawBitmap(linePressedBitmap, matrix, null);
canvas.rotate(-RotateDegrees.getDegrees(lastPoint, moveX, moveY), lastPoint.getX(), lastPoint.getY());
}
}
// point
private float getDistance(Point point, float moveX, float moveY) {
Point b = new Point(moveX,moveY,null);
return getDistance(point,b);
}
// point
private float getDistance(Point point, Point nextPoint) {
return (float) Math.sqrt(Math.pow(nextPoint.getX() - point.getX(), 2f) + Math.pow(nextPoint.getY() - point.getY(), 2f));
}
drawLine(Canvas canvas)
의 전체적인 논 리 는 복잡 하지 않 습 니 다.먼저 pressedPoint
의 모든 칸 을 순서대로 옮 겨 다 니 며 연결 합 니 다.이후 사용자 의 손가락 이 미 끄 러 지면 마지막 칸 과 사용자 의 손가락 이 만 지 는 점 을 연결한다.총결산
ScreenLockView 의 코드 차이 가 많 지 않 은 것 이 바로 이것 입 니 다.실현 효과 가 좋 은 편 입 니 다.물론 좋아 하 는 구 궁 격 그림 을 스스로 설정 할 수 있 습 니 다.교체 만 하면 됩 니 다.이 글 에 의문 이 있 으 면 메 시 지 를 남 겨 도 됩 니 다.이 글 의 내용 이 여러분 의 안 드 로 이 드 개발 에 도움 이 되 기 를 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.