Android自定义控件实现九宫格解锁

来源:互联网 发布:淘宝大v 编辑:程序博客网 时间:2024/04/19 17:21

最终效果如下


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<Point> 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<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;    }    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<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;    }    public static float getDegrees(Point a, float bX,float bY){        Point b = new Point(bX,bY,null);        return getDegrees(a,b);    }}
用到的图片资源


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.布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    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"> <com.example.admin.ninegridunlock.ScreenLockView     android:id="@+id/slv"     android:layout_width="match_parent"     android:layout_height="match_parent" /></RelativeLayout>

1 0