android 自定义控件 ontouch,Android自定义控件实现九宫格解锁功能

最终Android九宫格解锁效果如下

dd787a86704cabff194bfa045964914e.png

1.进行定义实体point点

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;

private String mark;

public Point(float x, float y, String mark) {

this.x = x;

this.y = y;

this.mark = mark;

}

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;

}

public int getState() {

return state;

}

public void setState(int state) {

this.state = state;

}

public String getMark() {

return mark;

}

public void setMark(String mark) {

this.mark = mark;

}

}

2.自定义ScreenLockView

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 pressedPoint = new ArrayList<>();

// 屏幕解锁监听器

private OnScreenLockListener listener;

public ScreenLockView(Context context) {

super(context);

init();

}

public ScreenLockView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

public ScreenLockView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private void init() {

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;

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, 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);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (!init) {

width = getWidth();

height = getHeight();

initPoint();

init = true;

}

drawPoint(canvas);

if (moveX != -1 && moveY != -1) {

drawLine(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));

}

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);

}

}

}

}

//初始化九宫格的点

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");

}

@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);

this.postDelayed(runnable, 1000);

}

} 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;

}

private boolean crossPoint(Point point) {

if (pressedPoint.contains(point)) {

return true;

}

return false;

}

public interface OnScreenLockListener {

public void getStringPassword(String password);

public void isPassword(boolean flag);

}

public void setOnScreenLockListener(OnScreenLockListener listener) {

this.listener = listener;

}

private Point isPoint(float x, float y) {

Point point;

for(int i = 0; i

for (int j = 0; j < points[i].length; j++) {

point = points[i][j];

if (isContain(point, x, y)) {

return point;

}

}

}

return null;

}

private boolean isContain(Point point, float x, float y) {

return Math.sqrt(Math.pow(x - point.getX(), 2f) + Math.pow(y - point.getY(), 2f)) <= radius;

}

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();

}

}

3.RotateDegress类

public class RotateDegrees {

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

degrees = 90;

}else{

degrees = 270;

}

}else if(bY == aY){

if(aX

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;

}

public static float getDegrees(Point a, float bX,float bY){

Point b = new Point(bX,bY,null);

return getDegrees(a,b);

}

}

用到的图片资源

fe9ff8c29d767bc27876962d4dd4b98c.png

579b19ecbf7f77381a27f850b5d87fb7.png

d11fa5162de2dcfe805e92d4341b2b05.png

4.MainActivity中使用

public class MainActivity extends AppCompatActivity {

private ScreenLockView screenLockView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

screenLockView = (ScreenLockView) findViewById(R.id.slv);

screenLockView.setOnScreenLockListener(new ScreenLockView.OnScreenLockListener() {

@Override

public void getStringPassword(String password) {

}

@Override

public void isPassword(boolean flag) {

String content;

if (flag) {

content = "密码正确";

} else {

content = "密码错误";

}

Toast.makeText(MainActivity.this, content, Toast.LENGTH_SHORT).show();

}

});

}

}

5.布局文件

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/activity_main"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="com.example.admin.ninegridunlock.MainActivity">

android:id="@+id/slv"

android:layout_width="match_parent"

android:layout_height="match_parent" />

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值